]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Apr 2014 15:35:31 +0000 (08:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Apr 2014 15:35:31 +0000 (08:35 -0700)
Pull more powerpc updates from Ben Herrenschmidt:
 "Here are a few more powerpc things for you.

  So you'll find here the conversion of the two new firmware sysfs
  interfaces to the new API for self-removing files that Greg and Tejun
  introduced, so they can finally remove the old one.

  I'm also reverting the hwmon driver for powernv.  I shouldn't have
  merged it, I got a bit carried away here.  I hadn't realized it was
  never CCed to the relevant maintainer(s) and list(s), and happens to
  have some issues so I'm taking it out and it will come back via the
  proper channels.

  The rest is a bunch of LE fixes (argh, some of the new stuff was
  broken on LE, I really need to start testing LE myself !) and various
  random fixes here and there.

  Finally one bit that's not strictly a fix, which is the HVC OPAL
  change to "kick" the HVC thread when the firmware tells us there is
  new incoming data.  I don't feel like waiting for this one, it's
  simple enough, and it makes a big difference in console responsiveness
  which is good for my nerves"

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (26 commits)
  powerpc/powernv Adapt opal-elog and opal-dump to new sysfs_remove_file_self
  Revert "powerpc/powernv: hwmon driver for power values, fan rpm and temperature"
  power, sched: stop updating inside arch_update_cpu_topology() when nothing to be update
  powerpc/le: Avoid creatng R_PPC64_TOCSAVE relocations for modules.
  arch/powerpc: Use RCU_INIT_POINTER(x, NULL) in platforms/cell/spu_syscalls.c
  powerpc/opal: Add missing include
  powerpc: Convert last uses of __FUNCTION__ to __func__
  powerpc: Add lq/stq emulation
  powerpc/powernv: Add invalid OPAL call
  powerpc/powernv: Add OPAL message log interface
  powerpc/book3s: Fix mc_recoverable_range buffer overrun issue.
  powerpc: Remove dead code in sycall entry
  powerpc: Use of_node_init() for the fakenode in msi_bitmap.c
  powerpc/mm: NUMA pte should be handled via slow path in get_user_pages_fast()
  powerpc/powernv: Fix endian issues with sensor code
  powerpc/powernv: Fix endian issues with OPAL async code
  tty/hvc_opal: Kick the HVC thread on OPAL console events
  powerpc/powernv: Add opal_notifier_unregister() and export to modules
  powerpc/ppc64: Do not turn AIL (reloc-on interrupts) too early
  powerpc/ppc64: Gracefully handle early interrupts
  ...

1413 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/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/iio/adc/twl4030-madc.txt [new file with mode: 0644]
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/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/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/video/analog-tv-connector.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/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/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/omap3-beagle-xm.dts
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/omap3-igep0020.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/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/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/include/asm/fadump.h
arch/powerpc/kernel/sysfs.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/sysdev/fsl_rio.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
drivers/base/topology.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/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/coretemp.c
drivers/hwmon/via-cputemp.c
drivers/i2c/busses/Kconfig
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/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_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/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/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/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/x86_pkg_temp_thermal.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/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/binfmts.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/f2fs_fs.h
include/linux/hdmi.h
include/linux/host1x.h
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/pm8xxx/irq.h [deleted file]
include/linux/mfd/pm8xxx/pm8921.h [deleted file]
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/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/elm.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/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/isa/Kconfig
sound/pci/Kconfig
tools/vm/page-types.c

index 3f0b9ae61d8cb710f39bbbe71ae3debbf0439f8e..70ec992514d03e91e7f5b1644929c5e195ff8d13 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 32b0809203ddd00dfa7f5a236f72b8c00058ec5d..62dd72522d6e4f5f2db69eda0991511c5cec9df6 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 47064c2b1f79b3cc4e1039323b7b43e9278735be..0aac02e7fb0e22e532dca3aca30c6fe7472bef95 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 8d96ebf524e96e0f001dc999b1734b7b97feda4e..b444f2e8fe32b3818d45997ca7f80c883a8619bb 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 ed1d6d28902213178a22fa8e3dd2f16d91797c55..702c4474919c54c29cb021a86eeb54e90f5bdffa 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 d0758b241b235d562d46c729cd969f53a8e47e3e..e84f09467cd77a10b3877aed3987ad6d8b19b661 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 a9691cc48fe3943bb42fc40797c524cd0843690e..beb754e87c6552e31077d08cb1f3e99d24a09c47 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 85e24c4f215c45136eb3393763dc802b007ac408..d50fa618371b3fa35c79bf3beb46e2f7dd4f4122 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 2eccddffa6c8fde5cdd4d5cc49cecab0b82b8206..0595c3f56ccfaadaa8f36d76021d8c6ce1a66140 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 ce94a83a7d9ae54e11bcc8483ac3a607516e0639..80ac454704b80903ba20dc4c00785d1f1eed9bf0 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 5108afb3645c49d948cd97e7c827b2d5599e499e..762ca54eb92989ab0129d227b3b0296cb99d832a 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 be675d2d15a73a4f784d7192931e187be294109d..a0b005d2bd95ce8d0251679adc90002a6e3b4809 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 4aa20e7a424e943e6fb65922d43312b8e47ca877..1061faf5f6020b354d003cb487178a69afd4fd13 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/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 efaeec8961b64bddba0df9d48af9af65e630f659..efa8b8451f93be2600cbb41fa5c8275c7ea5ddaf 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:
 
 / {
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 0e295c9d8937145bcf54c82646cabba06d6196b8..36a0c3d8c726a42a976867bb6a2e3a6df62e0d08 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 b381fa696bf95c7e35c5a850f2a9425d9f9e7fab..4721b2d521e4c62b51a06aff7bd34e3db9dda9f3 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 62fe69724e3b1da6a4b0b8f31c79f85e4dbdca93..c58d70437fce8b0dd11636a5a5f98946d8674d42 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 f69bec294f0200d55806109b0c70c94f7ae7c732..802e839b08294f6ef5f54c561b03c1981e395f0c 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 03855c8c492a28384619e4a7def0a0b98e527e36..b53f92e252d4a7f48427ca1e123381dc04e91e41 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/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/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 3289d76a21d0b2d01b81620e0c19fb10af29cf6b..57ccdde02c3ab9fb8deb5c60dd72fcf7d3081390 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 50decf8e1b90a573b11dc864c7b30612a5d5c5a0..f9187a259259f4a25dc80dfe08e66457228fa1fe 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 778838a0336add7028b0c5732a27af635d2e3011..2dad41b689af7a41b02cab8b3498395523b4a5fb 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 f424e0e5b46bb4b2668f33a74ebf5624a92fb6ee..efca5c1bbb1028245a6d75e846e96a6ecb4150bd 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 81ac488e375802d14864e2b9a57d826334c4eb08..71b63c2b98410cd9d657b9876897fcdb65189076 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 b8d284975f0f074c5e2c5d6126e1cf33bb6798d4..25311e113e75415e1962b2e157d3e55d5023aa1c 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 f00bee144addc5dcda3f7784c3b943824efbafd4..8b9cd8eb3f917e63074ba0ffae0e83b767a87176 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 67aa71e73035dd6029bfd8d75d5466fca297e53f..f6da05670e16d9dcfc3f8b7d50a1a4291ad8a974 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 c420676c6fe31d3ac66c1b63f165888ccd0efd6e..350f733bf2c7165fd13a960df68bbfebf4a34bf8 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 bc3478581f67ee05d31a58e73cf6fd3e6fcc2b68..b6c67d592be5abee31b7bed72beca0cdc273b7e6 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 09b583e38907422b027d62dee999282661c0f583..09c2382ad0556b196a3b4bb941b9e86597e8ebc5 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 13032c0140d430b3bc15a5e4a5771eecfc208f4e..e3155995ddd878c59d60d3519f2addaac716a743 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 271438c0617f9be8b1ea2d23a2ac17eedd483bd3..47ce9a5336e1b05c91944942095d42b094744087 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 9290de7034504186a1fedbd9a60ad3690abbfed6..a2f27bbf2cba1e863fa4a6baf92af2bfeb8a1806 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 ec8be46bf48da2146cbf2689a6aa51a315e1f2f4..9886c3d57fc2ad82d002e3fe3edfa60584f8cdaa 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 bfff89690c3adc99305af5fe37923db4748db87e..7faf310014373593fe25ecc44f5d218eb75d1c5d 100644 (file)
@@ -2945,6 +2945,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 +3484,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>
@@ -4542,8 +4546,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
index 00a933bb1f41078c44155a880718f5582233fe63..cf3e07516a043192576af45ab07fc3ee1bfdcaed 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 75de197a2fef8a39c61ff764bcbb0d5bef2f71ae..9596b0ab108d14de64763a0b7dfded5a7cddd4f3 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 5d65b54bf17a8001a6bc43d68c55331c1dc0e9b1..5246969a20c5fb323acf72b3b96dbc2976bfce4c 100644 (file)
@@ -1 +1,2 @@
 *.dtb*
+uImage
index ea16d782af58f5eb054d58b03c24cc033126dde0..4f31b2eb5cdf680cb6b26dbae5aa0119d39bef33 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 451af30914f660e14f81a6779292ca56d3c3ec99..c01ba35a4effc12b9598740d3eff14d234bf753e 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 66ee5527aefc08d7e5e3af13dbf553ce67d7c6c7..5faad17118b4360b59b6c7456be6a08b96f47c96 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 65690e7fcc8cce6b3d1f76e33750f49b788d0b19..2ff0347a2fd73c9811b92aa70e2b2b150b83cd53 100644 (file)
@@ -62,4 +62,4 @@ __switch_to:
        ld.ab   blink, [sp, 4]
        j       [blink]
 
-ARC_EXIT __switch_to
+END(__switch_to)
index 47d09d07f09371d62804680b18bfec19c5fbbe3d..819dd5f7eb055ec87f082188e3d7ebb4a8b683aa 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 991997269d02fb39d36b2bc552e91b745dbc2162..4ad04915dc6b8c51fe5bec1323c19c1c9650da68 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 e5f3a837fb35f2b4a37dc162f5b2054a1008ae15..71c42521c77ff0eaa0a17e6a52299839db35bb40 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 bc813d55b6c3ae5ce3bd2d559ca15a4adfb5593e..978bf8314dfb47397b9732235428a5f74fce0447 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 b64cc10ac918546be3a1ab57b15f3f2f1abeb8f5..3222573e50de6aebce1837152c91f7f209d029bd 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 9b2d88d2e14187c8d17b42b3f3a1ffa09bca3cdf..d36bd43fc98d8e29ce13537ea0833e6b68c4c730 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 9c548c7cf0014e1ce9c0823026039d60365b6192..b725d586210709d9020ec4cf4969d2187a3df24d 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 5dc802b45cf3ba84e3ebf2a9e847b583b8970fd1..3544600fefe6d6a480e432d5fff27fde69abbe0b 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 b7ca4ae81d88116a377545ae39ac9c3c8ae41cd1..8422f38e12183561855648e6c14fd8d042203185 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 39759e099696492efb582b80a34983a15b32094b..53cfd5685a5f9f80d44d180daecddf9a9c245c87 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 400c663b21c2bf075e977a8ccf3016fb7e03b5a6..89edf7961a2f743e74ee355f0b8a3f9c40ecd7ee 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 55e0a85bea78050f2b8c1606995b14a2c4f5169a..523412369f70a813e0d250013639cae6cb4c1447 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 3fcfdb38d242d47512a5aa9a174434d25d6e6450..79bfc81358c9a3199cf6d1354376a05926a97839 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 295cefeb25d3a85dec7728397a6d4bc6ec9d6f12..33058aa40e77d013feb8e195a3eddc5a539969f4 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 d71f3c3bcf24247653c0c3d4d702c80ce62bee43..19b76b61f44bfc2b1b560a240347aa435fcb87ff 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 d7a71e3ef55fce7d2812602077495baeb25149b2..5db05f6a041289676617cdf713385f3e30238055 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 0401f4dba2a226717bce178e34268a69a163be73..2f8bcd068d171644dd5bcd5266b34d64aa315de9 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 361cb58052bf28990285275222e6fd9b1c095148..63aa2bb24a4bc3de1e37131eae21a30e1fc0f097 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 27d3b70ee9e3afa822fba7a925b3693eae38dee4..63e34b24b04f7fbf35b4f78e7e17ee8b4a314d05 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 c16b3159b8138a4d0d0222114d638c77e1184227..9583563dd0ef7a3f0d4cd89765a20bb243b10117 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 5377ddf83bf8f99aebb33d2e5019e870ee5f2e18..22f35ea142c199082afdd8ba626bd7c5e0b6cd54 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 cba3570238783e4ecd4a83eb296666203306da88..cf0be662297e964186c378788ddbdfa00ca80664 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 d01e9a76c5da0c2ac034d85b7e1ae7880dbefd7e..3c3e6da1deacdaddd2ec75cfa2aa3ba8837b929e 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 f2779ac75872a4a44e2d03402fab7b6fe1a4b66b..7abd64f6ae21465c9ac74b22563f8f828a5d684b 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 d1c3d99dc94779255cf5aceed17cdade0637e5c3..1a57b61f5e24490ea198f327ce099c50fc0d141c 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 a089e6e004577bc7189c96fee69320aebeadd799..3d05eff67e25ea501410a3505788f513d20991f6 100644 (file)
                        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 6f31954636a1ea0454690316feac8c6abfb9b4ba..4c22f3a7f813a727058ebd4c283d62f1cfc04e0c 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 af9ae5346bf2e9f2cda58bcb2aa3604ebaba3e58..080fb3f4e429bdd4e1463527bbfba42e47478593 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 2fcf253b677c050269cf1c48707666d6fe05ab4a..6b5280d04a0ed24baad6fa81a7f353f826f82c52 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 ba077cd95e4e2a5f4960e2d831f8a9920228aed3..22cf4647087edc27c5f67f40f028904f65859530 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 cb04d4b37e7f0f241598645cd6bc2c215516530b..12be2b35dae9a249ca28b2eb4d3c4119d34d697f 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 cbc45cfc44e9911cd216629998a0fa3f747ad223..d2c45bfaaa2c5269b996ebd9e29fcf2d8031be60 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 9bbbbec1d63d83a3b92b878c926d2a3e67df194d..48983c8d56c22fe27271e1b6ff07b8c9f9e3cbc0 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 fe61976dc1a5f95fb2f3a91da1aff3bb9409ea46..2b4c1cbbce3351e1cb6b9711307bc684242c7718 100644 (file)
                        #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 8292ad0fe69f12881c9af5f28c905e2ec790f46f..19155bb8483502dc4505c2d08e55dea8228b007b 100644 (file)
                        #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 9da35c6d3411007f76a2eb9e31c5cf836397472a..4d963fb66e3f0bce4590e5885415916be9aba866 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 bd18bb8b2770ced6a65e5b3ad50dd79963d49c3b..f0e50a0f3a65b1c0476ec18db3ff914594c1061f 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 bc6013fbb7732682c1426a19922bc6ef86281082..b8920b6bc104f21f42dfda19d0ac63dd9db713f6 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 11ed9152e665274793ee83f50881efc2d9fbdded..8f5121b89688396d1b3fb4551dc55fc0c4395c00 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 a6aae300542cd822a873501e7670ea2dc273dd14..d88aff7baff8d5e7adcc865836649ca5ce1fb4b8 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 93ebb4007ea9a7dc9e2dee47b9b05bcf41d8c087..16d33d831287851ef8be0dca88b6360c6f3b46ba 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 f3d2ce4bc262350420d8ff57eb4805d2894ff87a..7375854b16c7a9dd39d7ab5793adc4f1b6669ecf 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 dadccc91488c64e94c06e9bf93b54bc5c294e26e..ea2be0f5953b53d0b799f871fefd8d6bad0a7931 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 9c7e23aa0e7f8bdf5d4d8b2f1a8d1f71ca2997fd..a123ff0070bd65138394fa6248f611ef2cc10573 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 b04c5f0fc2788372eded0cff24f15a0626d3d2c2..c3b73351cb7af37343c7ada35c6e43c581fd04fc 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 eca9eb1c59316ebabb8f2771905c5766951eeaab..62240f69b4ee8b1e62c0a94cc936e6fdcb52bd5b 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 3e8189186a5b50f9e8906231c6f46f2e81641a9e..e4e505f52ba0b2b477f008397808ab20c3ac14f4 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 ba1cc62467789225a0008efe0adfc1b32369c9c5..40cf50b9940cb13b02ab34173d479ac26cdcfbe9 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 a182008e3aebced89546424d6fda66232880a590..0f92ba8e78841556c683ffaebbae8a8df13347db 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 80b4be36f10a22bd69840c99e241eabdb756809a..657d52d0391fc4a8edd9fa445ffdf71457571dcf 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 b57e922f161465eab5aa57dcfd27704c1d699598..243dfcb2ca0ec191f1c6b27e3071c0098f181a94 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 9711a5fd948d126f3c457d1edc7ac720bd3c63b4..e6e4d3749a6e9d1eef343ec1f502c265a17c8e6d 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 835c559786bda923fe0cb8616b3031932a86bb21..d10ec334c93b4a3f8db194e1a929c711e5dbcf90 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 4bca4923fc0b7eef27e37532358fe7eb48aa1224..83f71b3004a85f154c22b92ec944afef5fa7caf9 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 7846a6bb08334dec2833ef8c09d60373a55fe3fa..a1bef78f030313abf99469cc2a6248a22eb70594 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 9dc5dc39fded63e41e1c5a84bd7b0a72c92dadcd..e94f9458aa6faa3630d5d2b7cebf9e522b56901d 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 2494fc01896a2f0dba01f57cd87e3bd0877ab8b9..f600d400c07d2cb7e615a13bbe9d02fe3959714d 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 f7af66b54cb216931f23718cc75754d269acefc4..5fc8a66c39248a742168250e2ca94bc5ebfa3a9a 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 130e2be952cf6e0ebb6fe137afa93832746724fe..215ad4649dd7d7492c7d566fda85146359291c20 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 14ba23c6115367b962922e5decd3afabb59e789e..ed3955a95747286ebcb3f705c107dc1b3af90423 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 fbb6e18436598142cf0e4ea7429b63965f2ada4b..ffbbdde7aba10480c12b41d552d1fb41da6097df 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 61035d6814cbcca9a7bb9be06e92e44446256f25..0fd56500077271402bb7af82f83526cd1dcef1ee 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 f17f581116fc15762d7092f1fada45e06e3dd7d6..bee789757806a268864d6dc1fe8ac8a0ebb97fd7 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 e868c72a79389c133559fc4c1599a197a33c195b..baf5afb7e6a0f7d49c205675d6e924eb2672bc80 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 f2d6f0a36d63361286a5816d716a600dc0d5aca3..422ebd63b619253d23c7a82d5fb14b322dc47fe1 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 67da30741a1b64a73ce085739209d7bf085ac2e9..720853f70b6bab01a650e39548872472bcfff0b0 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 c46f48b33c1409d8ea6dfe3c48327a00b6376a06..fda756875fa63e0fca640e99ca9a20ed789a20f4 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 2bb1d586664cc98ce88a0e19db8cb55c6b8b1c53..7ec328392ae0657cd78f7cbf64b75a28780b562d 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 f8dc7e8fce6fea147a9842824a8046822b70b180..6b7e89569a3a9ff8518e7c6ee856603f1e9fb93b 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 e085ee6ef4e23c146627798b9c7b98411a719f36..9042aff5e9e36662651e860259e84859352e24ec 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 ed0fcdf7e9905cb3050b50c6d467b2a5c8ba5f74..52731e221851137ce57ad7aa7b176cbe07e116a6 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 32c3d248868e27c152932c7e9baf98410a1b3128..905b70ea9939dcc629da3574fc30b4441e34cb63 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 fbc5c78c9ac75de0eafdae726b8bc061c73afcce..0fd6138f620301d7a2994fb96def1398f93b0a7c 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 0c8e553e0b9f8cafdc40853047d3e9b873885ed3..1325c3bc58e11934222dd7c493f1632535ab242d 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 f59c0b844e8855ea55989ad6b814fad125b45879..0c161ed6d18e6d77433c8bafabfdd48f904a077d 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 ab333284f4b2eb45ce2294b337d8e3196a081721..c39c3cd3ac348a414787d4db30ec6c6181f7f6d9 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 960a396f5929667162bf0bb867ac03d7aa85e302..ee9719eebb1e217989f04de5ae0b72e870c876fa 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 ca69a5a96dcc07bb760eabd43ff6a03dfc2d6db2..f295f9abba4b04772679a6ff232a2f1387572c27 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 ca4504424dae7e9f38cf8f59c953a0cda2570c12..9e44bbd8051ed1387a45eb4fca0b3f4aa49a3bf0 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 b2e322939256f528bfeb042bc420cd0de2efc1a3..87b7c7581b1dd5777642a3b87dd9002b7e68dc50 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 b1d3c9c0eff84a1c95a6f3c791e4069f48e12c7c..499b7610eaaf901114d3c7aaab36b53297469aba 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 16d5ab1615b1b1ee39b2148c01aa4b0b2df74d6a..5cd695f905a1c424b02fed524a9169eaaa5d63f3 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 9488209a52533432b7e42392d1bdd918a45dc840..e71d712afb79fd10e52aefcb913aef047716c219 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 88dbf9659185f65725f403a885313c8ff278040f..a6774560afe3753dd0f4636124c1021305b7a391 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 97e1dc91768374e7a7c5b56eb6752b7df5ae05ea..d90d4b7810d69edfa2283367aa7146edbcac8fa0 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 434fda39bf8b51f219098f207ce9cf35760fd484..d9e2b19b7c8deb16b344670c50174032d494176d 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 95dd892e99047dc3bb8b8967e54c380a783c781c..cf2b0840a672f893a3b2386154716ef54672dfd7 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 953f17c8d17cde75f73ef78ebc59aa0235e9fde0..346d21678ffdf02e8d677d8ca4516b642be6fce7 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 fa9aaf7144b7325d3b9b826bdea85b6f7968622a..1d4706114a454ae848e107c6f35a2350691948db 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 ec5ef891db6bb8f159bc25a8c98679ea27fb4cb8..520542477678a192240de08b8778ec74b75424f4 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 fda46bd38c99a7b529ce71925e862efdc3c88a5d..69cf5b5eddc95dcb83372e10f444df01825583c9 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 35f0faab53611214347cbec4129197747e38af18..c4dd400a27917b7fa38a4e6daf66d91b5e88e688 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 ff132ac64ddd0609f16c22021732c00355318bb3..f77695a82f647dbad92539be85dbac0babc60e2d 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 38149b63dc44a360ab3b0db2dfca4f23e64cc63a..71be346d0e3c8074d7be6542815610567ff66606 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 50a75d96f9394faeb60a4ca5d8ca0f1411d754c0..12f75313e086d4695ee768bde41beac4d3418de9 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 406f3a1e63efcce54ccbe6c409d6246bbdb7a887..b31b22dba94859087a019975ace0f505d69fdf5e 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 29c81f82705e139dc53a9af3f72b0db3d9e14695..e759181357fc5823c490696c23d047878c4ec753 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 3ccd71b903454a667ec116a21fa0678a6f80dafe..50630e6a35de394688ac59207a5c523370493388 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 2cb846c4b37f1561ac77f2ef687239987c9e6b86..c544b6f05d95e8e6fee2ef5b5f6f24d7acaf19d8 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 f9fef0425feecdd808e33bcbe4a457b8ece374ac..16c9c88658c81c48607de81e565fbe091f285e93 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 4133b3f72fb09a04c9f640cd214ef4a21a69c9db..1be64a1506d0164593bafc6fdc847570813b1934 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 e4c99a1836511b16b90de5b4591bea5dc9fc8e69..cc10cdd4d6a24ccbb9d02d12154da7eae25cb076 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 3a414c0f93edcd08d69d3a1aa2af645c098327c9..c0b03c28d15717448f4f713c083bbd891861f42b 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 6b594439cca5a68fa3fd8ece0484cc0f8b9d11bd..a734f3585cebdd8eda8db980fb0343bae16a1b1b 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 526d3735ed29050d317ef1327039397a4594d71f..1662038516c0db29d59a4a87dce89f374428cd51 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 e09dbe5f29015a9fc794cddb2f7ff57053594cdc..5963e43618bb0df3ca790ffa1ce65a9fefd86b0b 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 d42b14cc72a4516efa4c976a8e84ad47b97cbaa2..c7463aa0014b5a499d254028c77770f4ec4c7f07 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 f51214c0485884556151bfc63ecf0bdf88faafc7..ea75d011a6fc521aaf112b4d3764df6012c061e1 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 6c0d29827cb620b7a07235b48b74e4633d77d89d..ea0c7b2ef030f2d855df012af852cab54e509287 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 d817cce7e72de862081f57a2ef6b0936c64fcc60..26b4ae96fdd731b3e5cb82d6bb23a8799e9af80f 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 29bd7bec41768c328c17285b4876c428727d41d0..a41f2c99dcc85dbac9a2193960a6de63ce769120 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 8827883310ddbc05c765f17b2125e804dc2cd85e..512ce1cde2a4ca03c88350db6520581436968ba9 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 dd95f1631621722ca9d35a5d67269b152cb630d2..386d37a228bb71d7717f46c76d3fc4b7a05ab015 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 03a05ffb662f98d426302cffb4b08cb5cade7fac..08dfc839a6cfeeb3655f64d850ce1ed6e60d49cc 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 e3fffe1dff513a05ec2839114b1952c65801721c..c6d752e8bf28e2dbee2839915b46d10107eb047b 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 88cef505453bfb14aa21fabb745dcd781906ee5e..19f623f1f21c4134fc5f6a803d60b4a8d47f3b32 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 d261c62e40a68f8c885d6019e6a0ef27d9497c4c..0727a55d87d99a17c5e7fd0d8b6d8e2fe3b403a8 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 ad446b0c55b6076d5aaf7f095f1ddc91b5e38bf4..0c1073ed1e84c42577766c87aca3cd878f21c06e 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 796c9320c709f5850bb0679778a28bc488773be2..d7cfd57815fbe484283819a98745f7e26e6d1d47 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 bcfb70b60be6b4586b187e8400629e3edde3fd3b..72b04de182838f0e7e1dcc5315b9c9b4260778d6 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 a32c96761eab5be0ab6db221ba5f1a0d91634e5b..276f2e26c761708b866c0d6cb9bc4c69dcfd48f8 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 1399383315a36bdcaf06a79b0ef85a60cb8d33d7..ba55e939a820cb5792ee6186090f32d2f667f81d 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 eb1cf84231a20fd272ca18c9a7b9ee6ba8edea7d..e331e5373b8e36ee447f269859652e05de08c928 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 629db2ad79162173dec3e903fd4af568e16c8839..728c4c571f40ee20d879bd097c259fd274a37c29 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 f1251d4f0ba9ec5a5b42dfad33275e8123a227c3..4ab94ef51071d03eb96f0028a69c9c3b9f1e72e9 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 eb9c20d971dd56f0b752f3cf75830ec1743fad4f..d3324e4f372ec9d544f7c35a19d70f1fb679fee1 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 261c8bfd75ce8340c5054957d4a219f005cdd17a..2ccf36c824c65ff6bd97fd0fe65e65d12999f124 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 c0a9761f2f8a05fa6e6d46b6306e0f4cea0bf6c7..f8ce36286cea3f156bfe4e5c59cd2015655fb474 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 c21c673e5f7cde71cdeca0c4b48bf565df96bfd7..a364000ca1aa8a495f7e8b9bf59882350f41c6de 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 31c8c62239956a59e44bd650ef8f6c2eebdd7285..85258ca43ff5be5411c7d6d0c847cb030c9848ed 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 eecc4142764c7328108a76f5d02126281c44f845..f17bca8ed2ce610873076aa768a5dc78a6e0c72a 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 25c0dba508cc293712010c96d6c76938d198682a..aafad6fa166719309a92294498fa5ba14f6313ae 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 fb5e4c658f7aef9bb695012929fdc6768d7aa801..ef470a7a3d0f42807095accd162d841a24732852 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 f730717429758c165c13a14eb3651bde8ad22774..5b8ec0f53b57ec77848100a42a1e0c2838c940a5 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 4acddc43ee0cc60ae92e1506caf1915409fd94cc..3ca9762e1649d001e653468f98fff17a57065039 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 2f03ff018d36ce5291e513b9e37e5f81c54e2eb8..ba38ebbaced3cd0224caef932f3f59a5cc2cc5cf 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 8dcd35c4c7876bc9a476b067a097578eebb8237e..43f482a0db370628d2692de546c731015ae1203d 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 91d9c69a629e2731f25aa152de91dd17663ec619..b8237d8a1e0c86ac2d801cefa94e7f8f0c344cd6 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 94220d14d5cc8644dddee1de861dd12b0c5a0ceb..851bcdc5db04b51bc7e40c33a9ecf1975d1ea5bc 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 c8b051933b1b384ccd723267d99c9ff052875dff..7024c12f7bfe9cd15252f29f3502db75d92ebccc 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 0641113e296598c058cab739d94c0ae2f5280ec0..a952e9c85b6fad81684c4bd39418bd5623a634ff 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 4d5419b249da5353afb24edd23c8410d60f8079d..9b7734b1f975a4c0cfc9776749aecc83ace1cd10 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 3eec7de76efbb4650ea760f5163d495f47fd1f1d..d921b7ee659525e7d040ff5ea5c6a569239a64a7 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 4b8e4d3cd6ea62bc9c9047e869fa84cbd9cbe33a..4c36bbe3173aa0f683a5a982cc857c6f3ffa3e0a 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 754291adec338b34317d5c07a359741e5e298d80..3bbdf4cd38b9c4e38dcf8e4f480753e93858631a 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 5ad35ad94d0f819b1cf54f627d5df4fcfc58e460..059218ed5208e83ab40d44374064a53fdeab5568 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 bd2253d40cffe16363569384084bdf6d6d73e7f5..65bbbea38b9c9c0f7246a3c4fee4176dd529647b 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 7d9481c743f8439ae3a36256f008c45380ee49e8..3225ae6c51806af1590ce780a68ff67e6ca8ae77 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 93eed15a8fd41aeb4556117a932c9afa591893b3..8d80ae0116039b6c71945737befc4f88dea097df 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 05266b5aae22916e864bb21e1399193ff253374e..c9603ac80de5ecbc32ac80027d33a815ee6f9e94 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 9ea287666c6559abaa15a090ab37a0be0eaef1ba..8b3b3eb3cead2dffbdd20d6dd4632595e723a117 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 d1c55f8722c66cf6139222c3544c97700169c523..9d1b5cd4d34cc6f585b7f18a1ac2c5ba266c9b28 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 799580cabc787106b93041d3c15366c0a50b3151..597ac155c91c82d8706d5df93037b37e40745581 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 d87dd6d042d64309fedac698dd1a5b28a8448594..dd89a13f1051adcb18d3565a495a7d34b63b4f5a 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 a69bcb8c762102d9d778d1dfa3b5635e9eb19793..4dd8cf6525798cbaa817e47eb475545948fa2284 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 6890d8498e0becb308244819265647e6d400513b..379e8bd0deeabf8bb1e839ea6bcb11f0bc1dd12b 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 a313a7fb6b862e26b893ad8f5058e8767bf146c1..e88f4c53d7f6b41d4268b4eb51fad5badd514c2b 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 c87ae7c6e5f94636ab576a649ada006b4fb376dc..02d6d29a63c13716168c0a68b4bdfe55c71ef9b0 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 4f233204faf99b751682308c22dab254f6798fa7..d57d917ff2406c308b6b12b4790bf6654f4d900a 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 d929f77a0360629e599079048eab6061fa1ac5e8..583c2b0974cab79dfb08e7381836702688c2ed52 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 ad9d177626640377de6e517fe6d62db093039166..bbcbd3c4392689ef5022af42d0a09bb504be7253 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 34898d53395b10eae386e06fef3d12b9635fe93a..4c95b503b09ee3593ecfe1e2ca035788295b9f80 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 3450be85039943c649a3a96ff54376b39113f542..6489c0fd0ea6e43d5edb9c7c3cbab4e3cf51dad0 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 cb0f9ced6a93b2d19f2f7fa076146eb916a82764..be0763ff57a2b6bc5c21d7003cf53db75219ee0e 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 51c557cfd92b37cf6b7aecdfa50d212fdacc05ee..9849b5233bf4c7a4e3d6eb1d12a6c4215400a1a2 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 ad8aa35bae00e9836bcb96f0efbd3f8b781b2705..7f21c145e317f49e785eafeb1aea78097109e158 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 1a65838888cdbb37ec2551fd132c7c91cc66c511..c54cac3f8bc8d336723c752e0fdbcb97117ecff8 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 d3230234f07b980e7de341d2ff8f2b4912a8d010..0d1750a8aea40db16a470c697418d1dbd8b6bb45 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 b3eb582d6a6f1956bc870067188bb03a090fd30b..ad357254172890ff4170c2a32634f57ad831b26e 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 822ca03a87f796ae321cb9c2bd54ffe7380b5581..d5eaedbe464f873e5a32978ac6cf86eb70169188 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 bfef20f8ab4810b918739905f10369c95d7128b3..e73c6755a5eb6b324d06f14f4a7cf574d025c8ca 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 8e7fa4dbaed867ca45cb9c885db53543a65a74b9..d1cc2f613a78bb29e9969953402f856d77edd9e9 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 292a79d64146274428ad1ef251d08e1d78d46bf5..9d25dbbe6771e4ff9ff1f7cfdce782999f82f0bf 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 d8e398275ca8213a66890741941b266bfdeda3f0..81c34f949dfc63930125d85aec2687efba633958 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 cca063b110831aa4d4fc2f46afd6e9cc35ac30b9..a4afdc8bb578b826979b16431efef7183dee8f1a 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 4ea9b17ac17a9c5459617898718f1145eaf232ba..b8246227bab009e042ebb46e3a4bb093301ffcec 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 62ec7d4b38161af806f0b993791313d669f4cbe9..dcf2e55f4ae91e2ded094d156899c2815c0a00bf 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 ce6858765b378df01f66192b7fede05070054d3c..f488be55d650e332560e7bd83212007cac50c4a5 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 530f78f84deed250a2f96350254657b49a0166c9..2d64aea83df21a05a74c7470ab8054350063e8df 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 8b37c25ff9bd0074810fc942fcee38fab3cbab4a..92e6b77860970097b30bb745859d7a020661eefa 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 3b7d32da16046ffcdc238ba41b1b03a3ec152435..d8b7099abece7b9ccc44ee21550aa67423855f3f 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 f7a81209beb38b92291e616b0171eb9d3f94fa62..c43825e8f5c12c0ba4fd5e9b27181cfac8dfc4d0 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 9e978aae8972b18da9f012bef98e8ec1d408a1aa..27671489477de6cb6c37eeb80959475d38b71bcc 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 345be03c23db27203d4ce69bd74586a77e8f6ab1..03711d00aaaea91d4225088f6311ad309dc262d1 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 b924306b84775f39592887a632f76553297c5a57..d4e3f9d9370fec545a0cd7c3c8cb93e6d942789b 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 98a03639b413d834d08c5c73c0ef08cec3d37c55..04d3fd3658f3378e095a728b68de17653c1f1747 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 309023f12d7ff7ab5413baf14af4f580c2a5ccbc..e1eba0b7cd45144a8a3b6337ec0ea3ebeb688ddf 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 5bbad873c798a8e2168f50c33828f27828c378ed..9909bef5980045e3ba5eba0ec35187f4e2bbf0cf 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 6b51bf90df0ef0c1849fdcba6e476c4dc53d3bc4..05c97c5350a1b3fde396ed7a0a17d0af7d85e755 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 f4dc9b7a3831f32d43f0e53cd8ed9791cac665ad..93a42040bedb38a2bd21c4a8409a6ad83081674f 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 b155ee2ffa17a44452b1c80d71b8cc7483a527ec..09821f46d768dae2ab019898e6036da32aa0a279 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 af93cc55259fd69e240625b152590d09dbca052d..71e2d3fcd6ee3c17b589cdfb7cc8baf142605bfd 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 b0733153dfd294f178ff1818618fadbe63a1d144..8b410576fce4b42998bb8e9a0334de5ff38207db 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 f7af69bcf3f452aff52647d830e3f1497ad21dca..9c696a5ad74de262244be248549f99173f4c3806 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 21fc82006b78c3423c801b54ef5acd40d4f79805..319ff538560119beda233eaff71d007d7aae3897 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 bb516fdd195d463ca7627a2a1a69cb8d665a03fb..304ca8cacbc44f3cb27829551a4ead61472c5171 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 98a33c580ca1aeceed513f2af38b6742cee30f85..4c24c3ac1efaf28225aa635834e982c9f5a6055b 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 0f8cb1ae76074d2bf21d75d678585222019f2cdd..c3406aad294463718ccdaf1d83fc7636a0322b17 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 6e1a1a20cf6b4ab94a0f06f43d6470416dfcc879..5bf5bca94f562850ad96a9dcb654766d7632999a 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 639b49e1ec0586ceed662dbbfe3075bbf1157aa9..33ae3652b8da6984d68698da586f876082892df8 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 e082efb2fece3d7174592194f155946efcee03fe..9a16dbe121d11e3a24c7f72b6c55ca5db50319fb 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 547c6b590357609a2c4f1e6811cb018ea75b1cff..4eb20d78379a20777e65664f724770c9be015846 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 1bef6dc774782efe81b4b2839c9fa09e9f264b4e..0e9e06ce36b860ae8fb5a91d40faf31d917b180a 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 6f3400f3978a7544cf9138c4e2cd0d7dc41a7f85..e930d4fe29c71c2d82d2317bb6681ac8d3f39d6a 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 3e197e6ae7d938f23c98a88c66a09478aa97f60b..c27b66cc5d24cadc20e12d3427cd4dca3a10998c 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 c204b4e3356e80db01b736595d854075065768c0..2d27ba23a6a8ef17f39f45b903254ef3679be59c 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 a8f9dba2a816075781aa1e420543f7a0df488197..ce3e6a30deaab13bffb8d0c06a1b1cdb4bd3e366 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 06f1b2a09da7a1d2c1f4f556db86f299d872a081..7e282e3d603826cefb4f43d53a588dc3a2d55830 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 89e2fb0770af12ba7405ba8b116edb831b67c4fd..b7a1620a7e79cfff9abff9eec3f283316f524249 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 ea39e0ef2ae4c61d530bd2f7b729a26a6ad1e752..65a22cad7b36300811abf39b3a0d13020a479cc0 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 e7c2f2d07f193b0393052be2e1bf32921b804da9..addbf7536da45fe7748b1a79ba00b6df69f2f080 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 a20440ce32e6c39ee450d926f668f5638df0cca8..40fd6ccfcd6f7595671d750b57ea44066ddf4b87 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 fcb0652e77d04975f005e885faf33c70e2b291ba..8371cbd7631d421365a194c9b3d936fd8b02a567 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 88312458580d459946cd67a1f794a13929254374..84d464c90d3d34b095459e29304fb3aec1cf6a79 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 ddaaedde173d0814b5823e628bc1f61e07eae8d8..7afead9c3f30258b7869e69e0f2015d9c2921fca 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 c021ddc1ffb4b4e982ac01874953dbb7239ddc31..9a6d652a3ef248127723ad6b011ad021411690c9 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 2dfa48c76f54644d1c7efd6fb6e52bedacc02e70..ce288818d2c0f727cd56e70fd1d367ad7e050f4c 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 e9064dd9045dec0aeb784a945237662b0e37ca1b..b1531557637662af7c0e3bc576602514f3701d63 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 5a9a6a3063a8a603a73422f8f08b5ceaf30d8e82..3531f90e53d043e4ec6ae473570389a24b1fd6c3 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 661af492173d44f4861be750f42a93b13402b59e..c18268cd516ef5798d06824a6b0b436011ef3438 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 8fbfa06da62d867d8b70d944a7e195388ab36848..66727328832d7563f6e1dc42bc67ea6b48809ee2 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 0490ce36b53fd9237e754de7877f51f3aaffee97..9ff30c2efadbf99c8901bf0fe26f22cea73f63b5 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 1c0d723b8d2424339b74b706d9c258a974264a37..b99084b3f706e0e50d35330ab6accc9a0fcaf08f 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 20e08e65d46ccfecdf06dd03c150347c14c0f327..8ecc920fc26d1c3f8f331004305180aab88413d4 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 94b3fec22c280475dfe1f08d43cf00ed1ca571d2..e7fcc148f333ed56de86a92b14bcc0297fd798ff 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 e2db48a81ed0147738b27baaa76d663b29cc0f1a..c707fa6fca85bac195b824c7dcdb885074161f9a 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 386de2c9dc8649f449580a062d4d91c62fd3a733..9bb9bddd881a701a4cf387bf31874455d7e9da76 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 78b9f986a6e5edf7bbc29615bdf0be356961a689..ed569d8a6af3cb53dc8a90031d2e98bd87fbf4e7 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 2db731f00930d7b28d85e124744423c8a37dd8b4..592d205a0089c0b71922a8453914b5b26aa2ec35 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 6191d10acf33286f9f768e57aad30c59ef49bbfc..f5860a739bd8551fa60868b09ab61bb74b4c0edf 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 860a4ee9baaf0a124574726b7554c58e85de7785..6e91b20ce2e500fd766103ce1d11403a4257f383 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 321c00a944e9278479e29d588ac0ebb0bea2c707..8cc8a5abbc7bdd0852c1747f3b7924c0650e924d 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 c3e67ba94446d34a24b420c72804e029384948d7..0eaf11c199395573b3fd5c75df6431907cb964fa 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 8195e859210741cdd37ef00b0d8c6f2aa1070227..2de216c2374f34482f43008e20fab3eaffbb2e2b 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 38153143ed8ca222cd9d169ebaa885a7a57d4bfe..cf018ddcc5a646caf91d027d4cd79343d6e7c124 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 5e0697862736e8372c0ac5342e3d5b5b852be930..9b099468a5dbb496d0892f8c465131522aae7d9a 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 13ec6283bf597481e83089226ed13dfc35fbc37f..ab696ca7eeecc8544df4a9db2a1c74d00797bc9f 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 23fb33f1471baf0a77f8de33f4200d7961546e8f..07df7d4eea7282911fb6d1d7ce1e699541babd7b 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 1199180667c98af81093ff073948f2bf52aacbbc..b686e56646ebd4b8abe6ba53582dd4e595484f29 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 5ad6a03e477eae63aa8cc635981887febca71ac1..55ebe2bd88dd75972b10c5cae18ed44cb3a50fd7 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 c8841ac6c8f1908bf0af3a058c5d3a423a4f97ca..87b50ba64ed40aa640e74ec37e90e4008c0875e7 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 dc2c8eb030faeaf29f4bd7d32c87c803ab846e30..336bd3aa1a066868af57f131c3260629abdb27c0 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 32342f6990d964ddb6c798fc9159b5f5d4870b1a..d7778d0472c18569cbd89fbd9c70b5aa3f3a913b 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 07d3a9e6d79b5e5deab9a36220063eb55789ab0f..deeb0829b1298d29130f51e7bad4bf4a415c6adc 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 f883f9e4c5240ee923cbaabb3c57b88472983431..624eb36511c5dc226e4cb0817eb1322fc3011326 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 faa77f543a077da2c624e47638693b6566b146ff..48af5cac1902bbfa1360ee0a76918701baf83739 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 9fd44f5f3b3b40ff5f1acf497b613a36e153cac2..b1445b73465be0642aa0904df983183f0ae42135 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 af42e94f68467534f3879965c930c0c47610690d..a0f5bdd694919a86206ab210e5eb30827d297232 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 baaf65bf0bdd1a1430b565fce6c60302c4f95a2f..0f1865d7d4d8412918e99cbf92841ba85d0ec5d8 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 954acb2c7021d8eb9a90fe1e49ea5bc806f1f344..8155ded79079dfdee1b513299a499efe054c20d4 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 4debd32e3e4ce195e201b8869170a2533a7fd73e..7b3e9e9362003461951dfa737809f8ac916db47e 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 e17f1b07e915f924244032bc77c3ba2a5919adc8..12ea4b16469277d971f78a5b194079d67dcb7781 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 b2b46c52294c6d4d9c2a20890fafaa4b122e7fa3..195fe5bc0aacf56306ae01e87ed67660c0328646 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 15a74f979b4bf8c773b6bde25c65f0badf6afb8e..96177eec0a0eb9a879493a54c79b3613f0bb9b34 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 ec7bb0fc71bcfc8c19c2231c9bb0e3165f89e047..82f4d1f47d3b734c582b1d2b02b770039fb042fa 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 df77e20e3c3d00ee9173d4c160274f0e837c26de..0905cd915589a8fe2e122cf73c50516b313b9148 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 00c8361547253ecccf8ba17d6c06d730c688ca3b..6370a761d137d9d9055633c7f3aa6afa398fe360 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 e08acaba540269736777a7f7758a88d97f2aa4b6..6043062ffce73477231fc053113b9eb8bce12607 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 775d506b3208f44a9bc7ba02186efe7f168510c9..f462d1b51d973db98dc48492a2223b4eb065e626 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 2ca280f9ee53e3f6f6422fcc3605fa86b2f52afa..75fca63dc8c15b297f6b528dcb2b21327241d063 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 d269ecf46e264cbaaef6c9e1db6ddcfb57f1424d..7447160155a388705acf8f30223dbe3aec09e179 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 d278be110805ba50965f1e071213720434cb9e78..ab5e93c30aa2bde43b1ed892f0437b7b5d0c8289 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 28d24caa49f3f7720c63e208c4831c79f5433d8d..62ef55ba061cfe42ed5dfddd025fc8eecad0fab5 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 b1390534804888e46d4db065fcb0837814743e4c..cb150e8b433658feaa3ecf6f4d817bc5b495a953 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 990cf8f43efda908ecb1565cb5e8a786efe68306..12f1d43b2d68fbf28f8f0aeeb2ec6c727825eb88 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 d554169ac59274fbcaeaa2978078d0c71b822a33..7753249b3a959cce7f31b8c9cf1ba0b36c18dce8 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 a48b7cad6f1135c29742f39cacf23e359f92faf4..9f5b18d9d8850e886eeb44ca68b0bd17af4c3f30 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 8150fdc08d497122c49959b9bbfaf0090259c7df..56785e8fb2eb5f7e209b8713f3815b4c5ecbcf22 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 33bcae314bf86ea5f7a2deafb80625d0382634af..9c57029f6f4b4b9ba6b63ce2493eac4942f5eb59 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 6e580c98dede727175cf0542b0a1024ad0e2a5da..23c26f1f8b372e960f9f3dd5901a818a6a314374 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 caa18e855815eaf04a39ecb6eedcc572cf4d6290..480da593e6c036f68c20a827c7f499377dccaf27 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 f22041973f3a0a426e29424cb60ba68e042c3ed8..4867f4cc0938cba2db4a33bfdb464712defa5e9c 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 282de5e9f39dee6566bb6d220f378864df86e8b9..83b7629e4367bdac9a992f1c63d684074c8ef10f 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 e2e39e65f10954b8076b3ed01b565f0cb173bb0d..aa5a3dc43342a1d484a5419d5fa8388049348636 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 234ac5f7bc5aba1013f2ad62650baa05c1d1559a..0ad4e96000632c693df6c8faa736cdd3aaac85f1 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 9b8a7c7ea7fc1925610b4dcb11ca9f768057fd41..dae976f51d83357a51637fca61bd830bb9753010 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 2688f6d64bb9f3e6883e5a8a9216a38fd794d880..a0dad1a2f819f3365cb6d96ec033f47575da59c6 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 fbfaaba5cc3b2a079ae9749401d5602c6674cf07..0542de98226018a9427519d0eb6996714f3c0582 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 fabbf0d895cf2a5e133d804d5e8e05f0f26f79ad..33656647f8bcf566ea8fba54f898ec6fc71b2b5b 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 eeff998e52efdea93534ffb680582503f9f2a56c..7fe3feedfe039cda453851f1338fd56b100945cb 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 39eac9937a4aa1a89c176ef77d727cfb615b8cd1..b4d44e62f0c769746a538f70afdf9916c95f6bd8 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 ee3181ebcc9236078835ee18a48fe86c97525ff9..b0413e190625b26c0552e8a737479f52b3dd5c9d 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 8bcb93a2a9f6b1d09780c3154f6c656895451e8e..f1ecf916474a93e3a18dd604991a8915309d83cb 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 a759ecdb7a6ebaddee622ffd5a1d7900fcf5aee3..d8adc9104dca89395ae8016950e0715430354e7d 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 079ea38f14d9b4b54092a1ebeca4cd77dac27cec..cb058408c70ea6f8aee53c332a32515edd37c9f7 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 e1fc35a726564cc9f3526231780672d09d151838..5874716774a7eb17c5ebb2977687e29c3abe842c 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 31b36c5ac8941e844cd9f995b0c4e575219fc8ea..6bc68bdcf433cf06a68d52d95b063f9a42795194 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 0b243ce337147d51f7e9cb4b09d774f4cc33e856..270a6a9734387b6079e9348e17773214a293ad0a 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 95bdfb3c431c8467b105c616f6d5f9567505804f..d27155adf5db2b039dee51b9aa0de25e60c8967e 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 716a3c9c0751c18927cb1b10633b6effff584e7b..336ae6c602f2a6855e58c782a68debf350f49807 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 22cf0f4ba24871ad2697306aaec37a577496837f..bafe92e317d5d24c103bc83ea93a846cfadf19d0 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 87df68f5f504b5a2dd352f503d1af4dbf06c30ba..f729dc71d5beb031599aca72f82c90ec946e2fe0 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 968374776db9c32e2545b2409acc88322fe3f3f9..a034ed408252eb08e57e166ba6afed4a50931e31 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 adb5166a5dfdbe3a77e4e7154411e5162df1abd3..5a00e90696de525129a98d9e4a438ab7b3779a49 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 4f977a593bea13334aebca905c87be43223b2e06..5e1e6b0cd8acff9fa0b65ed6df7a6a91901450c5 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 461df93e825edf81e98d22683cfbf4fe7b4404aa..f20fbde5dc490595f57d171424c1c25f7ff5dd5b 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 d321099abdd45ac17b37bc32ae8399ce95bc6f32..28ca8cd8b09ed11766796b1dd12665cde74b8ea3 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 ca11ea4da165082fd3ab2f2ecae981d5cd7543ad..63c36ce330203669b597ff6a6e606a6066ee3832 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 6f1588aa9071f8db8642dcb8b32e46642381b38d..ae750f6928c1e559a9d6f16f5964fa37f559ce61 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 41b29add70b1be7a19b480d5a84ba25aeb79518b..9fafee6a3e43c357541161089387826d55e68018 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 7d10e55403c61da733c1e60c7922799063eef79f..f6cf745c249e60a604e8ab00f99ca75cb3af2b43 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 84c5b13b33c9ed2649a58d2a9d499d6d22ba0a21..3e6c0f3ed592a6b746610b9b6dd1986e50e1ace7 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 1e893dd13859817ae33e199b99f0810c59c49732..66f33dba1ebb3e520f3a2bfa1e4473eaeaacd7ba 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 f2794021f086f53fc509dea1f3136cf4facfe27d..6ea10bdb6e8fc60d7691ba5ff6338177023e94ac 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 0ac8bb5e7e85ef08760ca2fce41ec67558b4415b..47f7bbb9c15ace7bec2606c7d550f30e480c20b1 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 3be48f7c36beafa362a90f1c6c631848806779cf..03455b64a2458e28fdcdb724c42865f6280001de 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 e6adafc7eff3177b789395f6bc81f4ab62042e11..f9de156b9e65c992d51f32d9670c315d240797da 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 3d63269c5b29c51e69bc0dfe7714dddae71e4fee..9d10ee0b5aacf9d234de220e93a49fbea786a503 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 5423e914e491691a7a4d511a9ec2ae84caef8414..1f1f4cffdaed1ec43b3a3b6a8338b0b27064f6f4 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 0cfe3f426ee4f4523d9e34c85427cd7cd37649a1..3e667ca1f2b9360d5904a8c5bb7f0e4b48e7f8fc 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 458db8c64c28873f260aa59b44bbd96da7a3b18f..fad27008922fa0829f25af10d3cde5198530c87d 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 d310c195bdfed1d467abbd1f5933da703e207e13..b7d216264775511bcb807566047d9c69db26ff31 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 1ce95a8709df7763ad24f93f9cb21b61e44e34aa..0594a599f6fb1d9aafbacdb6fa5ae2178b30e4ea 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 313380ce632df1b9f1b9eef0915ef14deade0162..dee5d1235e9bb6701e0b5214da3482d5d334fbfb 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 dd01c6c435d6e2e01ecb92ccbd57cf09e7346660..18c8c7245b73b2b1e12ec3fe921266621763f8ee 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 32113b08c4d5fb16e401e871ec65080d61a63e7c..0a51ff4e9e00547b4649f43b2eadf55f86d44300 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 744f15d7e1315a6a3b9406f364d0a8bf78231cd5..e008de8b51b01927468c3f465c11ee9cd4b0c932 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 27ba61fb271045c1efa9acd2982c48ce7b60f278..7b629a3aed059649e5b64b071370b9781e2b75d5 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 fd47ace67543cd15f6be3c6b6799aefe497e4dcf..7dfddd5a1908fc517ac2e2f47359b787a08ec615 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 08b88591ed6036924c76d51efcf0d1d32c91210e..7c1ce6cf4f1f6ba931260d52cf2ea0000c61bfc5 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 81d5c26643d50dcff2067abdf0f2bb7a227621ad..66499fa0f7589000a2ddfd263cddf5037c592c4f 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 b7d66b59f43d4c7cc3ea0c733f809f966c37aa3d..2075b3027052c349f7b714036c2cf358d43871ae 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 987edbc30a0917cc2db2a035c749f42c5818b5b9..9784cbf8a9d20d2cf7d9706ca0fa5a571a720d74 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 1bd4c63369c16f96fd30762c1faaddb60acdf337..3ca2d25b7f5e023b917dbd4dd246cd8e3fe64031 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 7cf8b13486326fdcf64066cb368203668024d11a..6c89af7928892e0a80a99ae5e8960996d81babae 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 9ad722e4e087007df76e77473c5a5f98ce24be74..9a0cab9c3adbc5b4a58b92bbb2939952d896bd49 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 d31d426ea1f6327c96d77e21210d0b792ba87505..48d59db47f0d00eae37445ee3c22fc658895266d 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 ef9ce300a496e0dc1c5baae4c5f1a041d112ea2a..98c5b19bc2b06d25643bd904905cc834ef7b8661 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 a518543c00ab624f8df1b4fd22e66293943b8f02..6844061c7e0450afc2de82c1d4e6aa111ebab6b5 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 6cf8eefac3686bbd806225bdd21a1ff9b77ab0d6..88c96241c02a1a2fba69c67c3acadaffb5d498dc 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 6ad6dcece43bde52062c5c4563662586dfaef7d6..46cb2ce0e82a99a8995a6e24bb33dd3c55284780 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 1c5e4e8b2c822b37a140932d5b5378d5d2deb309..7762665ad8fdb5b461680ee84b7b224b77a5d4d5 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 ab63f32c00b2478d2cb0a2ebd062f946d394044d..44e0b8f34c1a8fc8d15fa019598be533e87df713 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 05fee10e0c975a166fec5b68d98d6e53cd1fae55..482585d375fa564ec2ff4e1bcbb7b87e2b15efe8 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 944e73ac485cf7d9e058af20554ec51d1dfd7f96..1cfb3bb9013154ebdd9189ea85b635023d84cd8f 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 5e077e4ed7f6aa23d0e8ed3fde50ad58c2fd99d7..2914646c87094868e41e9ee38db9e2eb881f20b8 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 d3ec436d9cb5f249eff5e7146f842d325980ff8e..6f9041ced9a2b131ad0e571091b4383757b3e085 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 b22a33f0702dd0159ed01f79edb00b7349f6b561..fa1e719872b769c79a959efc7b6a62321ebad552 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 54c1b5b471cdfa5682a83587a1d490455d6828c1..a9a1a9c9f9f292648bf294eb358f0bc8ec232015 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 a86bd3352bf823aa4919c301c7c6560e6682f7d7..48351b4d6d6bd8460ee83b2110f9e1adce7235bf 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 fe67415c3e175ce17de2be2e8ba7e03570d97cf7..833a96508c4e8fa96c6c3d2b3da0f16a8c1dd26c 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 71b4283f7fad532fa7a799fd9182f4733e4bb7ce..24a92c569c0a2b971870da21f9ff97e992e8bffc 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 d0d4ce3c489244f6cb2a0923295cecaf7b60d242..feebd58dfe8d005679860f5d57ee8df80a8fb442 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 c4740d52853286eb5dc75b43710c3c4eb0c07d3e..1dbc8d7f2e86553b2450e3f901430a116d7024da 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 a1102cbf2fdca0f95e30c2d0ae77d9c3ddbfd72d..c665fb7e4660a0560889258ab756c8a04f68277e 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 e2de73ee5eee529696b13914b92434cf5887cc6b..49a14b116a5f81fd771da20c756478b7e7dfd839 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 44012c3da53832c325e2286bafcc191208d9e946..0fab95e49f53b4f8c452b8afd3c114a5b4ad55f2 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 e148961b8075e96be5ab2f1b86ebc7170676db4e..e37d8106ae1a892679de32c16135044aedde2c1c 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 96cbcea3b2c96aa71f2c7ef3d59b3d3184a67e17..2f7345f7fe074a3854309a9909d4741d9cd30a8c 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 27dc1280dc10136fd3bcaed8ee4834b825112742..31922707794f79069ea775d53d294d9f02540fe4 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 0e7b01efae8d2979cdffac5bbf4e4a4030580d2d..325cc7b7b2fbeb21445f1e9160a47d16d5d87044 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 84dd32db28a02cff0118eec2bae837ddf56dcc90..d1504a4059c618e38f7f7215ff28e9de9e2180b7 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 b6da800ee9c2ddbd2baae4cf5812c681c09fccc6..855b220378f9f002730cc0874bc8d01edc112c82 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 6316ebaf5d9a581dae8ac9e5a6d0464d0f8ec478..1b803197d28be4e6bd71a34b5cc15c569bec16c4 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 4750984bf380a0dede5c0416330f448e1041ccd1..64dfd75192bfff1f92a1f9df37c396eaca7c55e6 100644 (file)
@@ -342,7 +342,7 @@ uint32_t nv108_grhub_code[] = {
        0xb4f000bb,
        0x10b4b01f,
        0x0af31bf4,
-       0x00b87e02,
+       0x00b87e05,
        0x250ef400,
 /* 0x01d8: mmctx_stop */
        0xb600abc8,
index 132f684b1946a9357697eace024fa866af43b72f..f8f7b278a13fcd181dd6e275ce40cc8a85fe3724 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nvc0_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 84af8241898764bfef6116d881c0425346684ee2..624215a005b02be92d803d377a58e65ce1e284b4 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nvd7_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 1c179bdd48cc2a0ddd3228a3e8bfc0005f1bf06a..6547b3dfc7ed09bac0b67b7b307f6b270936ff7b 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nve0_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 229c0ae3722844c16d39e33fb669b677bcefa13c..a5aee5a4302f59b1f76b484d25b84cfea2e6ca50 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nvf0_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 6ffe28307dbd6e420a019d0e7dd4ac891f531fd7..a47d49db5232ed8a06f1911bb1d646b709cc8869 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 e1af65ead379844459c52e9d29cf1e405523cd14..00ea1a0898229bf4b5ab0b3ee1f93bc23402db9a 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 b24559315903f56b23dad5df1aa3cf95f9572882..d145e080899afd788f27638f580d45b108dd7425 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 193a5de1b48287e05c732c28ddc066b8e4e5048a..6477fbf6a550ce84804d2b5c743b1802ed41548d 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 7a367c4029786f9d3b0941b62d697902b3681e93..2c7809e1a09b6c906c3bd58f7cd9e49287bc9fa5 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 a73ab209ea88c85121fe3580e9daa189b29de46e..f3c7329da0a04c8870ccba95a9b525c2ebc3ddca 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 b0ab6de270b2ea9d148b483b8249bc11efa27496..90d44616c876e3d62d23dc619f16a6d24dab4b3a 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 bc4a469b86cb98538e8411f9e5d628a781e079d7..30cab0b2eba1efe4a2cfd4ec94f896d7b18869a8 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 02845e5673147285e921ca7a2a639ae09b0cba7e..a6bf783e12563718ee9aec1be5fb8c204e55aa05 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 5052d7ab4d72826e733e036e69aa1f9a7a914baa..2a6a94e2a0415e6aa19748e4aa461ab7061b2c00 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 652098e0df3f618129278a5f0193bf0351f4bb6b..00fdf202fb92e633e188092b59f0c754c9f3c402 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 05ec09c8851758b63a7f46bf09596f535008736c..f7c0112171750253214a111931e7ffe3bb9c1c81 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 b1acb9939d95cfe460cea8e9aa2475d85256c20f..c96762122b9b40a45f1abc05fa670879e31f9dc2 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 5f6ede7c48928a799e3a2084371e5bb86a2388d4..92384759d2f55aaa3205b191e7d57f5efe10754f 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 e71a4325e670f69c4fce0893b973760a9522185a..9c0cd73462d953971159f94c0d643381662215bd 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 7b8ea221b00dc7bf0d88021fc5443ae059401cbb..a8a9a9cf16cb2e8e62c6f96e68e9d8ee95aeb73b 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 8897e08860853b5ea8f4db291a152534da973141..f5b5fd8e1fc9083b9f72a5b7ddb985a3fc0f6d0e 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 b3dd2c4c2f1ede9405fda56e08150949f8f556c1..672d3c8f4145d7b235afbebedf6f1de434bc4b08 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 4b21fabfbddb5c1c8f79c44e28d47f7821a846d0..fd0c68804de33f7da8e890b41b7007f0e64aec12 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 97705618de979e9fe1f810ca3ee5f557d5dd19e2..871edfdf3d5ba4b91c87fafef697d61244b4e8a3 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 c1270548fd0df050f219166ba2a425d30e9c9268..a32feb3f3fb67f0e1b662d4563ac2183805ca0b2 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 c5e6d1e6ac1d8adff24f25646a5109c62e541119..c086ac6d677d5badd33542e1c7a87047325e883e 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 083541dbe9c8147fe940d36177074a77d95ea9e0..8dc5051df55dfdddadc6a33c0e315369b6017a3d 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 ed1ac68c38b354a58211c386e1c9bc450b8501ab..e292271a84e40384b4fd92d4a25c2f2fec025e9d 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 d7ecafbae1ca1c1b0a43192673fbf5ae582ffa60..58c7ccdebb018787aa829961ac38f36059806ee7 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 a1985ed3d58d01782c03cfd1fb24cd6fdeee1e9c..c9c1950b77433a4332afa5811eb3f222124dcafc 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 3c6738edd127040337ff8fc53b6125a47e812ad7..72b176831be62ca009041d82155e21b6d9d9d1f8 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 69891d4a3fe7e3f50a840e4cdc2a34196bcd0010..d4a68179e5863c383640cd9c339ce941e34d9909 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 9ab70dfe5b02584e06de467ccd04e197cd2548d9..db9be803a87440f4274c46f791de5a4b885dcbb6 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 191e739f30d14f1c994db7028c759238b6604048..d0ced94ca54ceb6f755934b4495985787dcb2610 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 7098ddd546788c3adca970af4afc1a5a8d122d1a..bdf594116f3f2a1ab49698669ccf7a2b641c91ee 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 090d594a21b36ee9633462db5f0ee838547b1557..f748ba49dfc8c941c1fae80039c7d2a24b8cea50 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 bac5e754de35acdf838b571bf1d6e25eb8b5faec..3f30db62e6563d483d0a330aafe353692865c1c0 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 ef0c9c4a8cc3925f9f8df1279417fc028a39f2f9..e9df94f96d7827e446828106ef68d4667e361401 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 2d9b9d7a7992111cc1d4bd0ff3e60254bf52dcb5..88606bfaf84742c3c87a26d0d8387c29fecc9d81 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 de201baeb053aea79a6632289a865de94fc5dc07..acaeaf79e3f0fa797aa974831d6bbb367ebc78ff 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 991aedda999b083ec94609ab259f63ad1260be75..6c401f70ab99ae380b6c614983a997a9244a97d9 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 22ac6dbd6c8f7b2c249bcfb687974a3758b96c3e..d1585409407800b698cf909fea7a85c5f5c5d073 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 8fa34e8152c20b6ae90f2ca020f6c49a077f2cdd..239acfe876c3ddb4262d2e696cd4a59e1e06d951 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 6b56a0f4cb404c9cce29ee8e56cfee162908094a..4fe49cf4c99a37eaf32d79eecf029501cac353f7 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 7037eae46e445bd5d3278dfc70119dac180cadbb..052ad690b468da81ec1a95e04eace07834f70c88 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 98b7e6780dc7f4826c4eb946419d0ceb6cfb5d84..4a19c10e517809ab7b348803481bcb0c0e98a0eb 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 32b3d2131a7f0d14b0e37e8b9888e2b38cf937c5..3b8d657da2798445f620e9662467df8696304280 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 4689ba303b0bd6620ec080fcfe9fa3defad2f3ff..04bc9732644ccd706c72fdc055d534e61272f625 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 141c27e9f182788e3cff573a226786ee31a95c08..51d5076333ecefc8ba5167a3a2ccbedbd12a9b4a 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 6dedf1dad7f7bce5b71d33dd01111cac7324621b..006cf348bda767e8219901ec63c70aadd7d89365 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 fa7e63766b1b19ae47b8557c4581b77cb0ff0a22..30c765747eeaebb2c9a1526b31306587d64e4a5e 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 822a2fbf44a5b3d601d5c79eedb7b2af68654d86..f0e8683ad8405639d0406c3dc7be0dad153395d5 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 cbc7f00c1278905bcf24b2c7f8dc548c6dce7a22..1fc55c1e91a13b00869c9aa8a46ad2bd0f253e43 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 45470e1f0385f4682a654e0c37cb27212d3ba8eb..0670ae33ee450d7428580c280f34051b893675e1 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 9e1931eb746ff45f488a6c3be85cc5a90e445b0d..705a06d755ad2310fe10230ee1e160cceb2a9e11 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 edaf95dee61285d81d468060cd2b284b4da89cc0..da74c889aed47a01b9a51eec66e3e22a5ca7fe9a 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 c7fdb3a9e88b06cdcfa3151abf5ae7331c04e409..ef91b6e893afc4c4ca488453ea9f19ced5fa5861 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 f4ae8aa46a255948df24c3e4d2f4e259ed583d53..6eb97f16fbda97f40b1c0a9efbed47aacf030104 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 0391b824ee767d7629e333c56965366bc15347fd..8edc92224c84a2ce31b3c5115ff0f31f7c37e0e4 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 3257c522a0219026e5147d37725b1f6a30fcac21..16752192cf87acbb5e77a904fb3474e7f2de46d6 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 c4c1d415e7feb871329c275e894558f44c60aff8..2ef7747316291c1b40bb3bfdd84d87603473c132 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 c33c03d2f4af2f695e50e92078ea18c800d07eec..378e05b88e6f0c4562637d00e21aed7285c5b69f 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 ec0b9661d614ced3dec026e3460d3eeb07905f2e..8803809f9fc5fd8d2e87d5d2a5bd688d7b50aae5 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 b4b9943773bcfa710580244d43daf69a13d5043b..8a5555192fa5ea503d97aa11efc84ed6968c7e6d 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 13c5af88a6019d8b1e976dbe8c2e919b9ec8f6fc..51fcf79604173ad9a299bde564a782d63d097be4 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 80e584a1bd1cf4e4d6a32a8e3cbfd79739acd1e3..9ad01da6eacb7d5afd2c20e62440dfc84b1cf00c 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 95f6129eeede9e39f116844cefc8e324eced20fc..016990a8252c682f7bc7c93ead9fa8a9c5394979 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 5f71db8e8992e0c38ec2c46f945450d8e9778c51..9a5c07340263305f1310d1e6a3520808c2606049 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 8cf7597a2182d78ac6f6a57e7ee5e997bf1713ff..321db927d638c91a82141373fd8ff6af9a7be262 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 4dd4f81ae873d32c6aa47ae1c64d65fd252cae11..43fec17ea540b6c53af704931d4baf29d2391e4e 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 96f8f95693ce10654a1a4339a1e0eb16dba6848e..916fca5c78162488a23e65e11188cda9b2d0e0eb 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 c0bdd10358d76b748d4fc22e3ac480c99760cadd..240ed0b983a9714ff12da2b43133b76cb9befd20 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 0e3270c3ffd2296caad7cdbcbaadf9fdc7044be8..41be3424c9060d83c555f2ea99719ee5d40468d6 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 7fdc51e2a571bee85b6fcf707890c8e4138ca8d9..a2d669b4acf2452d86b32403936fb42bfaa7b11f 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 900fae01793e7884ee8033a11d6c247cbeb36678..b13f441c64314f24581bed203a9fdffd3602f624 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 2953c4e91e1ae9fea8fff60501dfa863d56c63ea..51666daddb948fd3650f6c14dd7d90963d8ce5dd 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 4c3feaaa10375721627b4bb00c5f95f0e6eb8a9a..8268a4ccac159e7d7fdd38f04857572448e6b81b 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 4aed1714b9ab7d289bbadc867f9af40b046825f2..b6dc85c614be402ca5d6717bea842c0448ce4b39 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 cc5152be2cf121a0901d323bf41b57886b56b27a..ccb6b452d6d00e34738efdf56e5c3fcb731e923a 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 1674882d60d5e842547e420f1baf48a13d534e66..d07ce028af516ace0b20db1418a7f9ed14b78c31 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 24011596af434276bbe1b9a82a26252229c20c5a..3ff030dc1ee35d34925b2fd5464f1236ad10d925 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 4ee702ac8907bcc3d486000b525ad61857cdf5ff..ddd83756b9a2df05ec527321a7391596634bd60c 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 23ca7a517246feda3e7dfae782683c88c2bc64a5..7efbafaf7c1da76a10b320acfcf3965dd249d11a 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 7903e0ed3c75c74fa2d2b46a71ee01a50289de68..64a42cfd371735fe6958147d9f07f6e235a5e417 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 27c3fd89e8ceb657595d188a8a3ff16cadde0edc..c90c0dc0afe8aba5c8730491b046232b8a1a574a 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 4aff04fa483c5e82acf1c66b1e63833bc23391cf..19fd767bab100d9acc90765af696be81241b71a5 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 89201a17ce752357444ec9f5ad0a4a42a84a79f8..75dda2b07176143605bf97f4c62f513ce0060385 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 d45d50da978f07870fb2bfc703ef509b4a2482f9..ab0228f640a5e86f1554402bcf5816d2e8a9a986 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 471347edc27eb869816e5d5cfed1ccd01f4c7b6f..fb84da3cb50d50a31f905052b4b85c2cbaf54143 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 2dccafc6e9db573814e43acff007c36c2c0da97b..58af547b0b930e2ea64e74b0966c7a81e11fba54 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 4313bb0a49a62a70039e1bd952a402e2ac54221e..355157e4f78dd36a40b7b56020f06e82a6ae76db 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 f466c4aaee9464c7ca4c16d684a4e7d4bfec5584..d2b8c49bfb4ae52d3599ad11a4b27fd66e0e5eb3 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 5aec3e81fe241e8ef1308d1b53feca75b3dfa34f..c8d972763889d9f99344b70f3166624d7b756665 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 3e0f13d1bc846610bf15557419525f1218bb0e2d..4ec874da56681f98e2bfac2584368819ed71e2d8 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 af9dfa235b945e3421701da24977e7a68fd133fb..8b929212fad791e6177d5f50ababb3fa8a1f60aa 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 59d52ca2c67fdf6caaf9e1729998f2a24b20813e..309f29e9234a91cd633a7f07f70131c2b846af99 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 798bde2e5881db484fd3797013aa11a04f11c902..41bdd174657e6ea34c4ad8a703d3288e721d919f 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 8691c76c5ef0a440b9391765b7c0ca099e2d6e2c..b95f144f0b4934abbb034e22c5d057a065bcecd6 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 821ab7b9409bb866c61d793c4e0ab9d63d73ec98..14e776f1d14e3bf099259d8d6b8f94ac9896f63b 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 c7e7e6590c2baeb29485e6a9f31b44f0631fc606..d52c27527b9a638a09307f75a8bd4b91a56c7aef 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 306364a1ecda1e1135a42205e805a8397df0b52b..09433534dc47099b5110208b9b5ee1398cc1991a 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 daa4dd375ab15367266d6f0041af84386d6699bb..fb187c78978f8d5a139359381870aaea8ad1cc91 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 4ad7643fce5fe9bdb8a479727400ae173475bb37..8b0ab170cef9036aaec2d1c11f9980e0e5284943 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 607dc14d195e3540f103bf798d2e6f0e10e5634f..e6eb5097597f6088dde34638ee9b94cca5bc8950 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 ea103ccdf4bd517205b95e82a1437e4cf510f8f2..f81d7ca134db19d12782f2005177639e64b6a44c 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 8d49104ca6c254efa86f4287059323be28ba3f29..cad89a97752709a68dbf4ecc7be99c78696c971c 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 bbb17841a9e57ad2fdc44425a26d658848892f4c..745143c2358fc73e920fdccd4c1cec50d54ee884 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 94626ea90fa57abc5efca249ab4d0d08cfc9566d..89b4afa5041c322a15afc67bfbba7f7cf2cef8d6 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 98bae9d7b74d1b3fe82ab41bc5f631d7e4acfc86..213873270d5f6b705974aa57867f0dff47b7901a 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 cf783fc0ef21920f7d0e50156bddbd9c24299150..5a9a5f4d7888ca5775a299293d2bc2f2aa47c8d9 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 27b0ff16082ebbbe10eb385b8bce24e127b5091d..b406546440da7cda8d7da10f7acbf6e6c22186e0 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 c7cac07f139b2106041208179d124d8ff5ba20b0..5c8b358f9fbad903fb8615fd7806235fec0e5bf4 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 a37b5443638223e1258b660403730a88a08f448c..287fe966d7de135161704b0e80ec38676ae1424b 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 351db361239db1d2800f845b2e9e9d02d541cc2b..16ec9d56a234b107742a13acd5a9684f62aabf42 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 bf6300cfd62d0799deaefbd698027cf8d811dbc6..d246e043421a0007b2427bc0513a8ccfe4a18878 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 7cf96b15377fa8f66bfbd048b08a6f1959ea68b5..6378e0276691cadec5cc7ff7dcc56f9dc92733fc 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 ca814276b07539741b53c167abc1a0bd5105173a..004c931606c4b88c20c6f86701d2600df97f255d 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 3cc78bb66042fc5509f26825560847374888288e..b6c32640df20bed4e954ec5ee2b12a4e43053251 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 b3807edb19365e79e61bf392a66c22156803859e..58f0473aa73fba3cd1e62a786d6776c7a20ccd3b 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 0b658b34b33ab1d2874c0c85a668b4fa48da0ecc..206caf9700b7fd8d13a2d7a4b9f52a1801dc79a9 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 647ef407921764692758c56e03f92b737202e317..6e887d004ebad7041e2080af850cc6ac2a12367d 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 2812c7d1ae6f21b5d4ba6550755b5ecc3fc8ef61..12511bb5fd6facea3f6b5eca1a5eaf43093274fe 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 b2d4c91e6272e4fb9dfbfbf669a55705c920eee2..53fcb28f5578d76919fa182488b32be8a1c6278a 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 e4cc9b314ce974fe5caacf91a000cb9a76a584d6..cbf7e3269f84882d1352a44ea402fa5dc4cbba7c 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 07eab2b04e81b5db420a6ee96152c8b8e94e4092..46b9d2a03018d854cb07c72d3eaeee9aa8f4a10d 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 e887d027b6d01fda8082305d11ff1b27bad06db9..f21db7a0b34d7d231bc278b1865bb83d4a1e1d72 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 dda02bfc10a49b55497479e3a911167b91397481..b8a24a75d4fff0e48e60b1f078f33e36c5209d94 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 ae637cfda783285a0f2638435e6620c6026fb534..3d55a3a39e82d55e093d707e8ff452dd9ab9b5e9 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 82d4f865546ed9024b4078d67bfdd947f08a1060..c566b486ca08a79d72256dd3696b0992c07b481f 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 dfb5a1db87d4a8651fd3a9bf7494d14287af7803..2b6e0ebcc13ab5e75b76089dcbcc00eeae08b360 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 044bc98fb459e46fac62b929696ad047f835360d..835516d2d2576a81d99346598874ff810116f35e 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 fbd8b930f2bec75276a5baf781653e658a023eaa..386cfa4c194dc40a75e13e23dde2adf040e029f2 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 f633c2782170b09bcc8722d1568cbe0a8c665f12..d0eba48dd74e1dc42e07b7e8335e421360fa4421 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 c37cb79a9489aadd38a84b2f59a6aed7e56333a5..a77b1c13ea43d6bea244e0da8666c82bb082ea60 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 a8f9b463bf2a4767d9ed35d150bafffbfa1dfe07..2e723651069bd7d084d393e25c741f122b4c5c79 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 b96c819024b3cdb7b2ea8f387c1e267a563ed8df..d09650c1d720fc74920577fc176f41f9b076a646 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 66ed3ea7144010e7c95bc0d07c01ad5499242947..3e49342a20e602e50f22c3068c543b7e19e9dab7 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 0b158f98d287136df1a4c3db11724798d2973d9f..cafb1ccf2ec3213b2dc394314dbece153d88ef00 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 402dbe32c23483afb3524d3397e3ce1b7c3cc281..832d9fa1a4c4ec9f665c9c99c545b0a3451c38c4 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 08595cf90b0139ee0da24f4ac3725e30dcbf9d68..19bec0dbfa38bf052db75cb52401adfcb29ac986 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 209b1115026379dccef518bf60ab9fa68217d9ab..9e7b25a0629d3a249720628aa697b9ff8a0f4a6f 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 8e8153e471c20a6b0dba28b38ce36bcd78f41a7b..ee738a524639e41e75c7af5279c583e4b3c7ee10 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 15e44a7281ab96f6b14592ed2e4e840ddae0b74f..f8050f5429e28b7b887528d3fb3ab623b6a85d32 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 c0625805cdd769b826d0605141f6cc80ce80ad72..adcf3e2f07da5ac10adc84a9c6c6d85b631ff87d 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 9006b32d5eed0433d336ef56e1bfb17c6fffa0de..dbd6bcde92de412a87379d7da23a4cea74b40649 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 12e8099a0823e23a1218c1e5a3f07e78bbfbfcd0..3a13e0d1055ce350183b1d345ef0996f27b54261 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 040a2a10ea17e8136a4274decc83de131ad79e3f..c8a8a5144ec16a51686acf3658dd149261867ac8 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 3e6804b2b2ef748e9727e34817243aa31e7f9210..5748bdaeacceb2f593bab46448ba5bf49fb940ae 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 8512085b0aefe0139c6ffabdc69114510ae3e2f3..02f7710de4700f59ae21b98f49bfc04cda5383b3 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 bebf31c4d841ccaa07b86d9bae96c7abb5c223be..e7045b08571567989dc9ac7a30d86cbda793cbf2 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 b5f63f5e22a324dd6b2714834d58c339359ab918..da041a43d82e8329fd2e58370e4d36e5a66b7011 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 9a124d0608b36f3ae594709ac92c4d4ad563b6d7..d589475fe9e69bbc5cebbdde754f5bafdb5294aa 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 59be2cfcbb472c1a538f058978645a0b775f5f49..cf0fdad8c278ef6921bbab3677c2cd596bcf1575 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 0a2f5b4bca430bf94a8d1e49dd9f786437772186..9a3567bedaaecb7ea7bb70d9f20654700231dc27 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 9239a6d291280765ef42b2e79e0c02f4719f33f9..683532f849311d1ca19de3daccb168b368d4c0b5 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 8b47b3cd0357cf7065aace2c90fa0751b203b506..3f0e8d7b8dbe3995a54862a48d25f812149a31fb 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 2da0e17eb96060e3027e185106e5f4366561d799..2a2822c03329e7fcefcb016e3e7bae5128c45777 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 d4a68af1a2792125dc58bbc955938c42174f723b..0a243f0e5d6889129fff88d3f5a3656450dd14cf 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 fbf4be316d0b675f89be45db4d820952af079287..299267db2898634fae3830c7be1180b1188ec737 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 fbeabd9a281f9a71c2e283df478fb7e3428a7655..a87edfac111f853056e718f646a6624559fe929a 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 0428076f1ce8723d025e64cdea77df33777288b6..e9e5e6d368cca5271a7260967ac63328ffc80ad6 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 8d220afbd85f94c6599a2ec0015c38ee7c87434b..d43f21bb459685b3cd26436902a45a171d412947 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 e38e5967d77bdc4a4c709cd44744887318cb87bf..71cef5c13dc81d0f01cf7c05acae927ef2ab18de 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 9336006b475d70b7494f1694d8661c07c2cd882a..36c717af6cf90830324a3538ac05dfd4306f3ccb 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 3c2c0ea1cd87a84e1f3414a780788d868f676703..c94101494826c898e83d43fb86c9df12064a65b0 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 c71594754f46fa18810d5b654d2c2d31288f6c3a..6f5b6e2f552e3798c6dc30e582ee804f9dffbee4 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 bf1cac7658f8d20333ce0cefbac8383e62f98c37..126332c3ecbb6b82c4f18388ae7a809ae7c6a28c 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 d452faab02352949da260252a4a1dfae763f1605..0e599f0417c06869e5b1f2bdd296914dd10f0d75 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 00e79c1f448cd578815bee682251e2bb80cc4469..1db5cc24ea914c253864be6a0f2e72697c08c23c 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 ef853e558036d55ce31c7cb4acfdf2479beefb80..bcf9895cef9f2c06870d1ef90c427fdb7d1303af 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 ffd4f792b410997630e06339a4307d087ab55f2e..2f3fe96c5154da0bbd99f04c6b809c18bba03f32 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 7ec4259ffdedf5ce488e4aaec9688abcff9df70d..2c7ca748edf57f5e89eacd22af50885a0771182c 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 e2c4aedaee7887b876db279e3c83888ea98f153a..486d19d589c8c49065b1ccee21318ef000aceea1 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 d3591694432dcd9ea4bfa4fd1f68f39da3f0666f..012ea8ac36d76becb59a450fcaf0a55ff0f88d45 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 57cecbd18ca88d210a6e83e61c3f3cff208f26e5..a3e4f1eca6f7b479796889498906c259d3faa882 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 d36efc13b16fbd0dd2d34be0561acd53e1282289..d642d4a0213491d099d5a7a4184fc273dc789a8f 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 214b7992a3aa74296eeb2a083b28398c08c3cb4d..4ab9f7171c4ff04a539a8bde7fc8a9dec2b9b817 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 c58eba33bd5f1b727988e660bf772f5b20b60e25..bd850c9f4bca64975e38bb25e429dfa0f614882d 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 479e9418e3d710a8c5f02fab2355f2e6991e933c..e8dac87585285ae6e0de09175384c52d8ea330fa 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 53b51c4e671a76cfc7f01cf73c5bba39531ead74..d2a0533527896bcd0b7bcf3124e37f54dc9a9f9e 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 dbadd49e4c4a62bdd32c83473ad3751452e4033d..377176372da893e79b7c108b15cb73f18d8adb9a 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 0394811251bd7e8dd75159d9d01b045d089d2290..c041cd73f3999a49234cfea09319822757f358ad 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 2ae1eb7d16355b3036e880d4edcaaa0981cbc414..cddc4fcf35cf4056e17c235b825ff87bd2e546eb 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 1e80152674b50ed62a73e3544c19855de29af070..8bb26dcd9eaeda79742bdf5aa325d3befacb417c 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 a75840211b3c9682da3be63df8a54385de238824..70ddce8358b0be2ff564b27599eb4cd537153483 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 0083cbf99edfd33bdfac9ad819ff4b12b1e7b5d8..4a223bbea3b34ee5489d25810ab04e14f1d2c7e3 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 07831554dad7acc3dae34f36e3a96e7b7f5299af..6b252a887ae2dd1bd91f12b452c4fa54b0a77c40 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 efb575a7996c2aed35e7046a47fd61acdbc167a0..931490b9cfed04b1365a87fb2d83c0526e114fdd 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 ed5ce2a41bbf02f34a8fabc8307985fe9763ed94..a89ad938eacf9a438a86ce0f2bc8b1e59d92529e 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 47b70949bf3af6683bb74552c0b91fa7b06d7a82..37881ecf5d7a9f74c49d4e1c018abc1cc2a9dffd 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 8a650413dea57c8e50212b41f8be00abba3ee8af..a2dde5ad81385bf932dd398bd522d1a950098f85 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 a055a26819c2b6b7963d6d245576e17b8d9a7500..b2b9bd23aeee620fee8610c490e41a6ef297997e 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 9757b57f8388d7a29fa51d04f61f5076fd149793..01d68f0a69dca74067b1dab583ab860711d6933a 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 22406c8651ead6caa629ce6ae2de963bdd0a35d7..a95d3a0cabe448672237b3c42bc8b182272effeb 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 ee3856578a12589d8b12e4133666d04134ad729a..c1559eeaffe9fe637eb2a1e31b1b070b6af29b76 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 e7af580ab977f5932629b8d45e5d5e68a52942a5..4ecdbf3e59da22ae8e6f887cddbaad1307bff299 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 bfb09d802abdfe0c9bcba38d879477610d44bbd8..b10550ee1d8958366b208f3e1927426663e8b91f 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 f31bc4c4864411ae8bd3267d27575c5444ac71e1..6d02e3b063756f6225078df7e00f981478ef5f45 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);
 }
 
index 38944e94f65fbd27692100d4d78b2868f13a2982..8df43c51de2c2d14434533cff15bc371f3d3a245 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 de17c5593d97c1d702563217f0932aa0a0aee6bd..014afab1d551eef640b70758f6e7ebd26a24ba2f 100644 (file)
@@ -936,7 +936,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 8e1939f564f4ae16f44d1f1b06e80744d303fa0b..51493ed4643b019a1cd80e423485a75f363b8dbe 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 4bf4c16de976be31f811ef8d367510c7dc530d8d..d86196cfe4b47091add5d756da6d3dbf7fded9eb 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 bb252540664ae15a6f74730226415f838e0d0434..ab346d88c68874e2ac06dc6f2911ef1ec6cf0f25 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 02125e6a91093e22bda1849bad209f6d3ebe8962..5a4da94aefb056becbca88e5110282608b26df0c 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 bfb39bb56ef1b3cd03204a9cd010fa81ec418350..e8b55c3a617042e91c2936c5576b45b6387f9fc4 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 7dca1e640970a0dfb7f28ad8909c1f3e4d7d26e4..841717a2842cb05d49429ed36ad0c51608f15148 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 c9b1f6422941eeaf628a0f7a65fd4e65053a8a14..bcfc9e85b4a0d0a702bef461f81b9fb568e528ff 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 49bb445d846aa76e206dfe7fb7d30ad5f24b6b97..33834120d057117f5b98284227ee0e3ec59df371 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 5aea5ef0a62f51eff03a14404569c68a7700262f..2851275e2656f8d1f012fee8a7f740b857c21262 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 62501553d63c4f7c2b49da5c73d79141d964179e..f495b8b57dd7b1cb93035018e7270d048d63a783 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 c71ff0af1547e573aacf17c6317e2e02224813f7..39fa554f13bbfcffc1f13b2bd2e8024371c317fe 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 17c13012686af663ba970f4c423a4262aa602b58..be91cb5d6e7860dc789ceb9cb8037524db0969e1 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 25838f10b35b2d08c295e18b27ecf4155bb5f4ce..e8af816d73a972e26307810ae38c514e17b9ae42 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 c319c4ef5d499c9f59140adf941987ac6d024bb2..6da8ec8ff800fcd5d7de55db28c7c0e77883c7b6 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 0680bcbc53def93aec02d2783b19a1e46c377280..17666b40b70c624029fc2a95ccebd71b10b685c6 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 8103e4362132a24486961bf3ac6fd80980210107..d4d4c165eb955902dcc56a4cecbe9fa6358ef702 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 26937cd010714b7c1c9e98877603616390b6e952..e70ae315abc775b921c6f4a5c352093867b443ca 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 81b7d88af3135cc7d26bd0e3afb842497b58024c..433f823037dd7a25eceb5a644661aec52d3ea5b7 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 d3e23278d299021f34bab4aacbb361d117f5a40b..07692604e119123a1f9b311b2611c5d0103daa78 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 be93fa261dedb4c808955c1830932f84a48b7524..3f10ea3f45d1ae672ca5adc6e96cb9fade1662c2 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 3bb05c03c68ded9f3e6c807a1c3559ec66830a94..4ee755034f3b2893899370ec1756d7e69018a8b8 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 71aa14a6bfbbb4ffd061aeb91df739fc70684446..5f13cefe8defcf73ed33e1c179de6b922f88b1fc 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 f53d5823a3f73f47001cb5e6633e0b76028a8607..e5fce765accbfc763b7b0c9a2bed115755691a61 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 e0859987ab6bc5c078c81f3ce937170bfc8a2bee..c5535f01846684e48120056d9a45483690911c21 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 176aa26fc787eae4ba7196edcfae535d22ae50be..a83eed5c15ca8ecfdad73e09e63e7b2e1ac773fe 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 5adede0fb04c8c5a82f7804d3138ab1f7a74f334..8cf7a015cfe501ddf3ce52c72abd6f45fdde579f 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 5d5e186b5d8bbbfed035725480fb85dc52a0fdb4..592db06098e69eabeb08c506cb3409c6d2ff2ca9 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 38ab67829791b1b8d7b5c2d33d24ac66999f2a3f..702925e242c90597618bb1158faffa653516eae6 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 41c31b3ac94059e4dacf21565d3d411cd37da371..29d76986b40b83081474d1db946af72d5cdc1eb9 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 90b630ccc8bc65fa7381439cd190274834c50153..651e249287dc4292a127d30de326323b989c3b17 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 5ee50f779ef60a86c1ab5e07782186e228054024..532eacab6b46ab78c69c9a73079db89bd462a0c8 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 b8941a556d7195e884e1f85d3e7017e89275a3f5..c1984b0d1b65273d64651f73e7f9c92fc0ef4e35 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 484fe66e6c884e7f32c9c9caca6473bcfc5b81e2..b97a97187ae992ebe9f1b55cb511636b012fde4c 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 b41db59687065921cf5843b745110f97d93b4ec6..bb85020202741d9328add483133fc212eeaa621c 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 d346146249a2d387dbb5485c8517b5e662fac72a..c79569750be9d1268c81dbfab12ed59573b01a35 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 c8f345f7e9a2b574c69d5c2d47fa3dbcf1390993..663f8a37aa6b27dd263e1f4d1c1345cff141b782 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>
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 281a827472754ad9b79939e67eb11820d70e3eaa..1cf27521fff4f2fe4a2892d651b5d47e4721286e 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 24ae3d8421c5196184d794a76c369eb79051b2ed..90112d4cc9059199ff1d4855bdadb42eb867a8f3 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 42ccd05445133444e52be15c4d380de7b4915539..4a91f6771fb82da541868250a6f85ccd76d24abd 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 1243d5c6a448568e2b1166ae34ab7e61b16e78de..7ceb3df09e25b8cda660b9307e9f23c5740433ab 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 71841f9181bd19f4ae6b832898353bc442999c2e..dbea55de4397d5055da2b3fe39283fa36abea1f1 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 2cf636c267d9413f77e39d787b6a47496ce1859e..bd83accc0f6dd4d14dd5cafa73da8d41a1086365 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 d4e860413bb54e1af55409dd7c8dc29e47747b02..dd4bf5816221a6ed79aed14b16cd42268b98be7d 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 2bc5cfb852042cd5e41e240cb5ce0662ebd0698f..6ce36d6970a4104484d0ac1fa118df96e27dedfe 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 1f142d76cbbc6fc03f44ead367c01a9b75f24c86..460a014ca6291fa10468f984123a3e160c4964ea 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 27a518e0eec6d04db1310e86f7ed678b4a762065..1f82d60b1d0fe077b735973b58cd34144be1111c 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 d360a83a2738daab514746692dbe03fee10a81d0..fbecec7f1e3df9f6d3a375714fe741d341bdb43f 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 ed718328eff1a52f1fff6a8e132f4ba905084422..e87140bef667212af51bb6e02fd0ee06744190dc 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 9aa6d1efa24112a6c5f28c37f4c42981e18f87b6..596b1f657e21d5d780cb1286bece2e366a4d1813 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 18a607e2ca0607d5fb80c765a53f5f8c13352b6f..a6bb17d908b8a4fa14267b7ecaf4bca75b704fdc 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 75316fb33448d6041d13e91f1c02c9321cd03818..6e88f25832fb23a13198a1b2f5ca8170b9e04772 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 0313f839e8fadc32228b9c892edb31a449b53ace..153d595afaacb50306bd017a1893c8f27b1c0ca3 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 84ce6b9daa3dea13b2adf8d07d907fb128d1175c..d0db89d13e0118ff16e97d65dd8672cd5d6ffa3c 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 981bef4b7ebcaa60b861d171a57f166a6218837d..35281e804e7ef3879d7c6f18d28d127d7b62338a 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 bffc584e4a4355f25f565ae6d0aa77244e556238..070f8cfbbd7aa7c5f7d043178948fda4cea852b8 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 11632f135e8c8d7a6f57206b4d09cd8b097815c7..1942b6f231dae3f193e41f618c6ec626ffc28694 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 7c1ae24605d936e51e0ae485c59dcbf9c2f5372b..4ab527f5c53b65ff2872ba07fcef30982a390f3a 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 624ff90501cde3c5fdf1e79f026db8cfa321eb37..cd01f7962dfdf996e8a4a695ffbd37db64a69da6 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 d66d256551fb77768fc9d458d5493c976ec25f30..e5eae751aa1b1f22e6747fd94bc85ba62174f8d8 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 2bef3f76032aa117d8bc2fa06451e832118acce1..a3700a56b8ff677d4b972de099ef6cde5b49ea9a 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 5ebcda39f55407e146ab06d811edd5825939a41d..5d49a21296187cc1c228d249b16bbbb7d79405f7 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 de1eb92e42f57f15f197c3ba21d1831ab6dac06f..adfa74c1bc45077e12fe78c1601b74923834fdec 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 77514430f1fe57d7156862ac0ef06b45d8fa35ba..e4ec355704a6c94488f57b567c93a75301d8fa7a 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 89b9d689153298f3b7a3965adf811a3d9963de7c..e21fde9d4d7e2d07ff8bc5d86bae597e69d1da17 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 096993f9711e1176e907685001260c8aaa39ff5b..6293855fb5ee190b84a23ea0eda4257cdd930344 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 d25535279404a7b7d101692b3f5c3f262cd0626e..e8d0164498b097be6dabe24241e24528712ab3ff 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 f992418f40a8d074277dd2798cb888bcc7fa404b..08049f6eea60e8fb00ab9fd1bf5a92dd2775afa5 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 ffb36ba8a6e050e0d8da73a7661cd7734905707d..b57ceea21513acd0e017b994fe2170905f80bf0a 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 01281382180b4c53182d2b07aa4bdd426de34559..1210bc2923b71386b94fd53bd4440d8df137486b 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 d83bd73096f67d916525371a5f51a3dec933877f..c68868f605883cab2d9507179a8fd0f340565ce9 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 d9fd87a4c8dc08a6b191e4454cf529898c1688c6..66f0405f7e535b33f02f71586ffe4bc13b5f1ee0 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 d1dd6a33a0500831f78012f9be91afa0161e4574..1fd4a0f779674475513837c4ed18a7e30f3a259d 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 ad19139097025b97839fb7cbe123a1261e6cf876..524dab3ac9381f4d9efee0bbbfad98cb9171888a 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 624069de4f28c067260fc4fec75c35b713fc5c84..dd22ce2cc9ad6a901d85d28215fcdf0825a0550b 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 e1f2aebaa48955035f6eef98f31e7640202461f1..2cceebfb251e7b6959758b8c7a6bc19b4c9a6c1e 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 0c51b988e1f8880af884995540cee3c5ac91dfca..f02603e1bfeb974ca08a101ae8bb58927c1d1f81 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 42382141206222152d948ecd19f73338e1a30a3f..363da96e6891cea8eecdec0205160d960eff0cd7 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 687bf27ec85076c2d735418714c12c537c2dc498..c63ecbcad0b76714c00fbdbc484bccf13b557488 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 4adc0374fb6b5736ba23cdc77f5f8ebb2bb7117b..487e64f411a5df1ed0a6e971f4d915244a52fdda 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 d38b6460d50565c21fa46978d3f2383d13299e6f..018c75faadb3d30c2de119608536b1335d175fa4 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 45abed67f1ef176da4469ed5f9b78b1c66e874c4..69f2112340b19dc94639ff90bd87114490767168 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 310dc7c93425587095941d76afcc8dacbdb1fc29..fce23fe043f7a4cf1edc998422689d2a45e0982c 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 5434d8ded015dfca0e8a19199883ce26122fc421..6ea51e549045592072016cb9387981373b0aecc0 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 1adba86474a52f7a4fed630bd08f300cf45e3398..a4c477b9fdd600cefc6b48e0dd67472c08d611f5 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 46d195fca94267631887f76d7d98f7d67005f3b7..5ab71f0e1bcd6e3b4ae279aeded4e8c980bc9524 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 d6b2451eab1d9f0db5808c3ad837ac2f6f604499..6a589f1e2880bb32aa7cbc01d202ff8c24d65603 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 93c507a6f86245024d6b1e79a54ca2f8ad8d78b1..7aa682cd4d7e74d28677a53c2fc5291452ee3ba4 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 98bb5d5375d741e8159497e30b704c0520533f79..cadfbe05187316a93449d69a0fb6773720a3aa06 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 36da518915b52b8220e5e6d23ed57acc6738ce0e..eb0242e0b2d9903df922f811e41b9584a39cb212 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 d11109762ac5ca311a1f9bb90711bca0855ebc83..217c25d7381b7589238833eb3303c9695a10b19d 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 10196f5a897d6b31674232652869cb5617e820ec..d597e89f26925940c4f66bf2a222ad037a1dfa15 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 9aad854fe9121aaa821181bffe64e819ec0e8498..cb4d92eea9feab773be54de8936842c350f5aa66 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 93525121d69dc17876f70f8341e6f69faa251b12..146b6047ed2b0e066ebc5961244993927d7f8387 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 3051c4c362404bab5119dcf00d8c1e7321e4dbf3..b7a22a612a4628adfaf647c27a9013fcbdabe85d 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 39cc4181f02538a438b8fc427e00e19c1074fde3..b6f1aac3510cb58a720cb529302126ab9596b3fb 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 5073cbc796d86c3a04c4f22d83b01c2f01b1d114..0b2ccb68c0d0240efdb9c5de9189f8e89a4ca890 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 2147e733533b611a44c88ca3d53efee5ae8f5e01..7d4e7b9da3a1aceef2ea5ea664cea4e0d94752c6 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 34c0b16aed5c4e2f7d61a22d3fdeaf2ca066a632..d201feeb3ca6dc7ffe1380840fb0f826ddb0ec10 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 3c7d6d7623c1cd5557b4dfeb38e80e03fc6e2abc..1ca9aec141ff01fcd90dada11986f25d2fbaae4b 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 a4bee41ad5cb3c191748a04409c81ad5414dd1f4..f1cf503517fdcff3e8743fd3ec2816d85d4fcd80 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 8611eb4b45fca90e73d84db280b55301640fcd93..4936e9e0002f384701493e0cb823d73ee3f20fb6 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 c36e9b84487cd36b55d96efd1d17c6db9494c0fc..4ce181a35bcd3eedf39c8fd3a5c617306278ef58 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 2880d888cfc5c260aefcdd5caba743d05a292ae6..bc5c518828d2bc9edb8796521c0e2e0ebb016497 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 94f55dbde995974213b48158048a92553bfc7475..b7a24946ca26274a291ae99b6d844e586487dd2e 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 f2f64addb5e87119d8b72e9122565ae3ec9150f9..4e66726da9aa8bc55658bed57a3d56d1849d6793 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 8eb6a36f125aa6e3ea57d6ad0f27d8228e3aa34d..4615d79fc93f795c869687117744e01653219478 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 babb02c4b2204ed0c5881a3577084c2ea826d5df..35cb17f57800755fdbf1032cf5c155059f32215f 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 fec31d71b84e03d7a84cbaf15b4558c16d413e0a..f68a7bccecdc65878fac3ed3056ac499099992b7 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 bcf60800c3ce7f5e0489972ebe7a3e3f83d225df..ec549cd9849fbc426c598240e6fbce6fabf1cd1e 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 50d9161c4faf49959174f603efe69db4ed969334..cb45d2f8e208425cdaa8866ebdb96753cb80f999 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 8e6148aa4539a290b4b3a4cda8883f1bbba58f92..117ce333fdd48f68525bca9b8da5fdec36649894 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 ca6369fe91ff31fc89bd382dca62261774310ff0..bb77f750e75a3b1cfee16e5ecbf95efea95ead1a 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 31ee7cfbc12b628c9599f3d0c78b3de23185dc6c..e78841a2dcc36be4923923f0251b72a6de830809 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 e9a4835c4dd9887f8546c5e95ce298674d5182a3..dba262bf766ff197c3afe9db1c68e11ca12f7a2b 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 9715a7ba164a042abbba49fd842e9400a677d6fe..9d01c4df838c91000dda6793ae231b0dd0992062 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 daa2faacd7d09f99422fa3f64fc6947a7f4f92cc..3d7c89fc1031aa258c513a2e1d299fcbfb358c40 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 9ee09a8177c67feae055da60dcb033e9bf76f4c4..e8a5fffd6ab248bdf5329eb9fb7bf1674a3b92e9 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 bf642ceef68172b4575d8e9d3263320e0fc7095a..1ff49b80bdaf7e3a454c02574165d1a59a04a72b 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 90f871acb0efec737c918532bbdd350ca7969220..2c98f9da747111f28ff8e5b538ebf4c2de39ee93 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 2a7a0b27ac38dccc511abd296742a767ef183133..7588fe2c127f293329a7cb347969e567f59c436c 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 f0918e7411d99147fd67c26c48a8672cb237437f..79acbb8691b59c94131944f10d80c4103fbc9594 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 8e1919b6f07449f007c0b1766f4ffcde5db4c0f1..093c29ac1a13f75e3dbbfbc354e62e9e3905c8e3 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 6547c84afc3a4bd6cde72302ddb1add10141b154..d945473c388201ee67cc5529fd984f5799792512 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 1de33b5d390358b58a2cbaaaf6991e08ebcc97db..635ee0027691eb771bc31eac771209b48987d8e2 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 df7400dd4df847b321bb1fdedbb5ac522e9c5b83..b1a792fd1c23682a63d313b0982ad1bfe666131c 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 233b946e5d66d95a2cfbabb19985e5f8a75efb13..d1cbf26db2c0142d99f538efd543818a424a218d 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 4b8e89583f2a5d83f366515f4ed0fa5c4239361d..cf49c22673b903fac33d0b7c2289d26f28a7efe9 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 c818a63532e774035e7f81d748622c0b21810c2a..111ee46a7428e2d8ad384973bdc03e2cb2305122 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 0ba8b0a288381f80bf0aedfed61e9b3933baa604..7bf416329c1973ee58b6c3511f90c8aecc5a997a 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 95a6ca7d9e51950078d5c5f6a2e7281ab18621e9..d9f85464b36298646cb1af16a4dd59c3b2cdd886 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 4b18b87655231c3f5ee445a30dc8b85fcddb265c..1e65cb6c25912c6a2c55f5eb964e3e14230c9060 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 65b735d4a6ad8aa92dc4cea9490f3f14fe9bbab8..afaab4b2333f82cb635d26ce1522d91895912631 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 05f4f5f52635b64668a3397427c6b1483f057eb7..3448cc033ca55c33d4f8b002b2828d88b6185cd5 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 adf8acbddf56c1ec64905a4226e558e829684b91..0966bd04375f1aa0384d4196b368bdf9345dc1f9 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 ce75de9bae9e4f9eb219247bcf9cccffba9c0542..4a79edaf388547d0cb5f7ca594d8ab20841efefc 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 e9f7c656ddda9728dc4a17497185b2457d8b6d9d..e35c8e0202adda08dec6d53586bdd9f7da89a2e9 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 f31bb5e9d8a962918feb8f88ccd274039a6b3389..7b52a88923ef2e53fadf9aca0185e2af492aa7be 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 7902341f2623670422078c8b4ef4f62c5ec4c52a..2360d81507774aa772f8a6b5bb94f9d0345d64ce 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 28f89c41d0cd25efd451b4e53fcd4296607b5f64..4d989ff6c978a8ad67d36afbb7d2df5ef6632929 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 a72688e8dc6c288cc7a9d40d68bad02574ba7fd2..27e8c824b204fc8ec16c0f927216676415ca5834 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 66b05e62f70a8bf8b7652b296bce1ef57d5b8699..1c44e67c3067c7640e64b5586b7abe721a0bd78c 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 a3bbf59eaafdf2e31b400336129e3731e0d88364..243513980b51511a9c3054d71c8a270d63949cb1 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 89417ac41083e59c2c44512ef804a7861ef1d1cc..430bb0db9bc4c7e376ab042d8544d0dc3573cc28 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 4cf5fb922e59de283a65be28fae893eb7bfc9eeb..22b047f1fcdccd9e4c2d704a669ed41ae7895771 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 6d1f6ed3113fc1a0604e2db595989bd48c386c3a..a8497183ff8b079985b7930fd5eb26dc9fb44813 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 0d862a5077ab53d01d7c4b6ffb6e4d5f9ed85725..c55e316373a12671446973b1418e1e7c153df350 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 89d1d0556b6e83a44fc6986d080072d6e93c2045..630a3fcf65bc8113fd6b67ce587f26fbf46c9774 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 3f021e054ba1cc004dacde3f82df06a4e90e03a2..76665405c5aac32d57eeadf355007cbb2b50cbec 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 a27ec94877e4de2efbdb84db2427672e2e809bd8..b7361ed705375e6e49dbfde3bd9d7fce4f0c97a2 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 76f1c9357f39d2a285c6bd8af17eb2c4aac5dcad..9559829fb234de4088602ca6e942e8dd11bd43ff 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 7dd62fa9d0bdd8c64554ff3f4e737bcee3b2c787..396c200b9ddb3b6d534e571f1827819e221c65e8 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 61b51e17d932a5c81db81fd99f46c7411dcf79c6..d9a0770b6c73d24b65ae35fce4bf3ac2a7f43343 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 ff7cbf2d28e3aca513a21999334ae01352208600..1753dc693c15af46c1dd84b5ab1cd63347a99e05 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 7061ac0ad4287c0d84edb39058ef6abc295e43ce..0305675270ee53ef168c15f5c93db0d06a1df87c 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 91245f5dbe81a7d235f13a2dd2edbe741508d584..9b60b1f3261c1182e2c799e2affaf7e49605015c 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 c9ae692d34518c97485114cae2c685e6da81e11a..f301f059bb85c1b18820ee45cfe4f08427ae8ec9 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 d3a6539a77cce19ef7ba6f311aed249c8e1cf87d..47a1b2ea76c45a0a02d671bc4d7bee042ec1818c 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 e0221c6d0cc238543cc84557a9ffb176a64c23f3..cdb005c0094df0b58362db0e6a4b462afd2f0621 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 2e8a20cac58848cdd0e2afa6201f3f82f4a88e84..a54ba0494dd3e9105abea0368303712ff4b35c8f 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 5f99d22ad0b04534440ba1d17d247c9b127caba2..2d0550e08ea204c2d9b1b1afbdb71cb6b554e4ba 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 9cbc567698cefd0d3933f7c77198d4ccf34ceeeb..c062f1620c58d419514af3ce7b81da8952e11546 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 9f849df4381e1388c87b89bfc33f2b350ce54dda..15b3459f86562d2211dde73e507197bbea04b50e 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 1fe264379e0d10b57ddca456ce16b72c23535ccb..1990285296c6c4d669d7e79074f84e94e8a6c346 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 fea76aed9eea41c0c9dec84b59ab585cb703fea9..a68b5ec7d042b369d4a68bc1c78e35b7793e1c1a 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 49af8eeb90ea2b3cbd5786bdd075727b20a9a327..6e8f90f84e49dbe47dc9f6161def01c376d1ac67 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 981a99fd8d4285c2b443f81a320c48f8826871cf..3478e19ae194567520c93838b8a1ed2316c8d061 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 4b824b15194f6eb034c4dd2ef4a7f0ab3ee9c3b7..5222ebe15705e14f8a0a9b2598b63ebb3672752f 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 0bc91e46395a8d84ad8c989b6d2a7844593c3ba0..46b324ce6c7a8d46fe335b6b994db455e7c3beb8 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 1abd0db29915bf69b8618b7c267dad552573a74d..a1349653c6d97dfcac5341b2ba38bebde27e8f2b 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 f404f55b31917a3daac4ea9787e130786ad6b3b8..c461f2aac610ea6a8580c504c9a2fbb9dcb92979 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 6287f6a8b79d6c37b3b93d3509c11350c57d29bd..1d41f4b9114f8253e780d279799dad0ac0d27e04 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 34c294b42c84e0353d4049737a72c9d3b57dc61a..80c03b452d61960cbe3df5d198fc409e7c49a9e9 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 f3170008ae71b9b84de3c05b443a600d96e4396d..d5e105b173f0cf121894fcb5105a5afedadc16d5 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 47cf175430082c792424fdd1fbf52b353279f60b..ea5efb426f75f013708ab35f94627eb5204e9ebe 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 d12f6189db46ac8773923941d2ad68fd93ee9a17..86e020c2ad0deae1e615ec30ec77fdb592eae0d8 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 a8d01785461577a519e5e3c7a749e2fb027a92ed..c48f640db0061efe76d74c8df09be47cd5fe440a 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 b0c9b6ce48540471760a824126c4e9e709e8af8e..27a8d735dae0273e81c226e00b8eee5d482244f3 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 e2f597ee6261cb143e0f02ef05558734d24e2631..1ca91f7092b176cc8d27d4f1f36ddb694ff32d28 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 0126f714821a126808670de2655b0017461b5346..a7bcceec436a97d702cfba0a6b63e4862484eb7b 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 1c8a7f4a0ef52035e8954197db31024815974811..e7dfa434bd9607e2ef9dd6087e2244dd7f8a682d 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 22a8b72910986d986b5d41690ac1f81c8556bf03..c7f014ed96280c6c28b58f30a529d910d3317ea1 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 70cf1591676a2c2acb0f33bec628e83d719cbc30..38c8c2221e4e1c47022d14d6437cf14d3c8e054e 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 61a3ceeb0d3ae081258400749cfa68110d24e7a2..de5b4a5f43b62f9f732a5d192a446affc039db0d 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 4bfe3d458dc0699b33057cd3fb3a0287e0c7e81c..4939e8c7272ec64a012803769df48f9a1a093f62 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 d306e010d3ea9799f2e60420918041d2a9339cb3..b17af980392984b16b1fda94f31fbe4aebb09492 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 ea6b72d40b317f9eb342b66c9a3c762b8f6f96cb..cfa4bc0323580a3117a0b572b1862937e2b256f1 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 756d01535d3ec317e2839402c919f240633159ae..1fcae55dabba1fa46e0721480538821e40030e37 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 1feb0fba1b436bbe13ee619c296f434895c7dda6..5c6c34191e8dc007494b9a6106b2fd93be8c7a13 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 4a24b9c1e8e3f099604f4704ddd45a85e2e7fc13..e19e9994bbb557c194dc4ddd2a8508732dc7a734 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 2f2fe5eeff63e185f7ccf7e4db22f1308b52a65e..9c246d701a956f5b3c6a5a166199ba01b4df7e37 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 326f94d6b0798881780a4cc70ef600cbbd83d0aa..c9be6f52c2541a061e3d86e154a56aa6f1050148 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 243c3d52fe5e616f75e829df544e3182cbc3ff7e..ee6089502a96301cfd2fb6442b05d9f8598ac468 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 e74f85620c68b30bb753a2dcbea5ccbf75cae1af..711cf114df8376be2d6ad6182b3c4ac1f0886151 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 5a29b9fcc93035fa11edad15378b16f5896aabef..3f0be04df071d1356d87a43fec71f49b29877b57 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 ac080c9dcf46b8c8edb6823e1f3088f05c05145b..6bae2afbaa1533f924ff51a852d0d4be90a71117 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 431cff844a439cb0267e3943fa38da3bdf911e1a..f950d6e85b5f4fa4f5f3664a48e5ba05d3c28d65 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 8252ca14695dd39fe50faacbbde56c800131f8ed..257c6e59b4603b54ed44bca4147daae1a8a8162d 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 081fd7e6a9f070c683deaea799437a2e459b94f4..9ea3d9d49ffc55d4fc8c9679a5e3e88e7e5549f4 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 eb6f2b059821933b3faedb0acea9f67c7ebd663f..fcf2d48ac6d16b5f5ec31b11671b73bd68a98e8e 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 ec7772e452a936c2ffe9c3e71ae116a9b9d2a80c..b5b1bd228abb80a8da816cceabdfd54289a0e699 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 27f33ef8fca12f88dada9945cb8f8f58f3e46578..5ee3b5505f7fb3d53aff30d0e79a146011df9609 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 d18e4b8c07314e8ce53bc163780e42093fc7480b..74de2bc50c4feca760cb9b0928a24eb288108610 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 9393e2d6473d34c2671318329e3c0da12228fe86..29ed21b9dce5934afa12025789f23ff81bd23a37 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 4a291e756be944cfc0dcb647312d520891bca4e0..b4e9a42a79e61cc58d9dc0abd50811e0db694d48 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 d5c936cb217fe78bc0f072a602f22c14b61e388f..7e33686171e3dd9a658922610133b62df74fb359 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 f317c878a259e235090c3cc20bcf33a5c15f575c..d6f14e8717e89e87d978131f3b05d8696536a02a 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 27f60ad6b2ab8193bdfc9781334295d389d8ebac..c7ba4d8b928a53f49848a0fe75f4431792350886 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 d3aa91bdd6a8a35b95a840f818d95a5717f9e25d..8aec8bda27ccfe2c11546c1f0405c51fe111e7b9 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 aaecbf34774803b71fb1dda551990b2ed4bdd480..2bbdb7ff7daf3111104fef6c87f518e0c8187d38 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 9f19ae22944c2fbecaf34c4506da9de2d6cc9fe7..2412a0dd0c1312baa732296e895d5d9f1a63eea6 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 6c0bb099b7bfcc0b1edc974a184b327efad74372..157921db447a4ef3f3d0032feb56e83922867c94 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 0d82f731d2f07a6ae1c1d0dce9990dcf9835eb39..121d1049d0bc3d6a7cc383e0dcd9fc0e39e490bb 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 96e400c51001aacb2ea7aa90cf28d3f28c3b9101..825c019ddee7680238f65848d73dd872985c0f93 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 570f7ed2bcbc6a693eb9749ea3ba6716fb3c7339..918fec18242496ef7eff156aa6be0f9c59964f5b 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 895c252ae0a826478a3c3a497eed9440c257cb91..f5f7944a1fd1d6521624e8d4a5f62971bac916ed 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 cd620c6e43a05ec8b9ca81a1f6566b2697166a00..f5f4ccf50d90be5bf6905c3b7e9efccc64060c7e 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 b679e33adf2d93d69e23a39c16044b1c535f7a03..911dcc9173a6b1e7f0b8e8ae508d8d0ec4bd652b 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 59ade34bd5362ed5c69de01b3828417456330254..21d81113962bb81df71783be6f21ac4b7ef9e7b1 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 8d02f164c8c6aa56846f8ae9f1a3c110aa82d73d..ec2d132c782d20b2ffa0d08e842131b56511cbda 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 0e6c0333f775775aa776902cff248abddd9e3a5e..0ba1b7c997603e43fd24a99fc2e97f689f0515a9 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 461208831428e4da609606282af2b56f4c3c81f4..4baf2d788920484f5f9fe8d752d9f51ecf7b63fb 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 61a6ac8fa8fc7ab00dcc7c33cea47981f2509d4b..b7a506f2bb144e1c2e59b0f84c4c736d90dd830b 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 d5a3de88ac59df240b09a6c21937eeec7754dd05..dfa12a4a0a48ffbaea7f64e4b0c95e6b2ca38932 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 a16b0ff497ca38b818a20fd729a49533393f4771..d8223209d4b1d58710dccf7f3eda0b429655fbb4 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 952aeb048349c73ea9a6d9354015163640e47d4b..9852bdf34d76963453914c2c251786332ede5e0e 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 3952121f2f28beee731618ae915a433f16e16fa0..25b23b1e7f22ead9bd5d3d6d5fbd7e6aa2755ce1 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 d9a43674cb9479eb673140121e60ee0355acf409..533a322c41c02ffd8b1dfffb98b3f1b60593e757 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 f1eba8c3644e9800397f6d1b7cc3e6ceaf723bbd..cbbda476a8054e5409b843616e1a1b7023e63824 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 c36cbb4537a26e0348a44f0ec7a65f64ac3204bf..6dae1ccd176d60446f45ff8c35d24c1a17e34f13 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 307453086c3f84bab8edaff9a201e0da3baad819..6d589f28bf9b849bae629cea4d61f7dba60eda2d 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 3182c0e68b4204cb2aec089b5d960b7053534757..232e03d4780d1b51386e72ab8df7e65af279e8ff 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 29aa5cf6639b40372e0206420c724d6628285ce4..7041ac35ace85ab7f91d96b21f0dde3c54840257 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 0f59799fa1050fc6e061f0f7273850bbc1297a0a..aa3cb626671e4a573a4882580cc3d834664751f1 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 e1ffb1e2289896a61bc85d76c535184979789751..c660527af83880e56877de2a703526c3f4d18622 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 8c44fdd4e1c39f836b2c8a9b2a7a025f1844d3b3..834f9f3723fbe3980e8a9705e8c1d0f86936eb40 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 da95f61b7a09e850e6d28de88aceb4493d7157b8..5ac591bd012bc8cd3653cdd8f9ca731511a051d1 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 17543383545c162f58425fbc8629a99f1c5a717e..2e5e648eb5c3dc3bd82bea5ce8dead051864cf75 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 6d59006bfa27e688d37499b88f45e28a22df24db..16b54aa31f08ef801f2aa852b9f00c81aeffe9ce 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 45eda6d7a40c2030db42fc06fa2d741f180c254f..766410a12c2cb209a224fcfd97f63a055fd20801 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 16796be53ca59450ebc81a074c84e7e08955a71b..00d6af6a32ec9a37f204705da091122e7ddd7151 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 09c7afe32e496c7dfe20d527106c7a184248c3ca..66075a4ad97900edbfaf98775d484c31c7496200 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 32d519d8a2e210316fbf2af3b2c0a842d47a13b2..0b0728e5be2d7cba589a935159b88f9d26f0b2e9 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 dc66c9e023e4f3aee170db98d2bb549819d99abc..efbe082892920333e6d2c703fa58f0a275e3d87b 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 ae6d14e82b0f439153b5e62adfd4d0c2ebed73a1..d94ba0df9f4d195cabf677fcdcd41cc01096c7e7 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 f4f050a69a48fff9a707c28d4a024691a5bdc814..2b4d093d056319424369f01321c710f2c9d27185 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 68288917c7371fbebc314a0085e691580f57a711..e90cfccf93bd9e90a21ef3c22ebfa9b54e43b3a1 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 4440f447fd3f2329b28f8e88e44e10141e4b30c4..51cc23e4811147ad537fdc0d49ffb2f07bcc9dcf 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 10a4ccbf38dab2c6f26407e7383815986f337bc0..06150fd745ac65d72c456b1fe57f537336f1064a 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 d8801a95b6857d514fc27e440af8d476513cae3e..7866cd05a6bbee4afd2478f3737d0ccd8ac28975 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 a55ec37378c6730efa476d3d6a923e37ba10ec72..c9c2b887381ec2504ee48c673cf113e396f3b04e 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 834fce759d8075313261dfa0a01c76ba9c2cb5b3..216d7e99f9219317bd0f2567c898925df77ec68d 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 66cba5a8a3467768edeeec573d2a61e5bfea27cc..40707d88a9452aea7c995198c2d94bfb1e9775c5 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 25dfeba6d55f8ce8752fa551fbc823535077ef0e..9e81c630dfa76469cdd452e179882403a93b03c8 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 1b8001bbe94778ec09cfab5ecd8d08136d384a5a..27695e6f4e46629a8a888f38bcaf6f0e4ceaf1ec 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 7cadd823bb311643a6cb7042222870767224b4c9..7d66fb0e4cca87e2ae9be18fb5f7862d1df1a2af 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 d260115c0350e91be14eca760b813032e5325fca..3750031cfa2f796af344e19f4cc234df5f0c1eba 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 cfedb2cb0d8c461e7283396d17ab0fd84d919423..c0ebc4db88492e343a4e4f37d8e26e2b9f4480b3 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 22548f56197b52cf06b343285b7e7beb7d74cb10..158b5d4ce0670f31aff64638274b8ae6849655d4 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 e66e4808719f1958cec123853cd7224ee103d479..17742eed2c16f2944f019cc8d43d245286ed524a 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 082afd78b10788ed8b1645f0f26c76bf3ea91b0e..a1b810230cc503708fa5cb2a91598684a0c3ca41 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 efce2bbfb5e580976e76d95791dd676a29d71dd0..f5157d0d1b43772e95aace234b4ee50fca9ade3b 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 95c6c5a6d0c56e20fe6bc2374dc8a3bed5da2b72..08cdfe5461e3f726650c1216f801d6620694ea5f 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 3387664ad70e5bc3bbfbad03a2d934e98d0dda7b..722c2bf9645dc50e60267b9280f441cfc4b38d5b 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 6db7f7db7777dffc4e4e0d959bf295dc0a03a6d8..4e508fc83dcf1b0b9b2934e4cf69506e063b0f6e 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 fa8da4cb8c4b9a3aa647f2a4f51467fc86549fc5..e93e4ec7d165afe85800bf6acf68f01178d9d836 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 293d0486a40f7e8560b25d012a7a2398ef4e955c..4aa521aa9bc3a794fbe52625e689b93140ed38a5 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 2261ccdd0b5f04a37be390f1b28c8703fafa86b4..45abd60e2bff54323139b037ed1bccd1e534e96e 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 3de9d20d0c14afcc6f96462bae23be6c488df570..b52c12cf5873af10702f7b1afce7ed3b53f0c709 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 2b7c255bcbdfffa259a5d0a45b9207626e455d79..972fd0ef230f9aff12f877a4f056980ad07757f3 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 fc3c558cb4f3d5a71b8ed03016e838cf5ec84cdf..2ecac8312359062268986adfe894f6320379bdd4 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 0dfcef53a6ed830e442f8c174ea166b0d1b2eabd..60e7d5448a1d8b705d6a30fb0ea266e0989d3201 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 ea0371e854b4e0244537cf3d33f5f17e147e8a25..b90dbe55403a4dbd0c1504c399a2285d416b6063 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 31ee5b164ff9f0ee27fa291bbd45df49e0da8d80..383db1fabcf4447637fd4153915e9512054b27ac 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 28cea76d78c610eb0b5584aacda41e5ea975de5a..ee829d360468597f3619b5ef1b3719b1fd942516 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 397d459e97bf9f1ee2107c1079f02a282a47e5fa..a9409d19dfd4815f38907b93f84ad3428383b07a 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 b0649b76eb4f390bea393344af07a9e65dd32211..a161e955c4c808f01ba69b5c93eaf4943344b316 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 c4c79885c99344aa9e999b5562fea34954356276..5decc1a375f0071ca00a81bd5d891b507e86ffba 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 976a7a934db5ddf8ba7843f28cc8e1311c86a632..b1ae89f0f44e53878a7e37aea926c4e3a201c2a3 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 7caac5f2ca9eec01fe1c92a494c8f32ce238e72e..085f548be7a31e53539f844f29c0ea74f87c2a83 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 5731682d7516aaefccefd96f0c70798f478d0c5c..7091204680f49383ff269f0b8c35834e2c5297d8 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 856bdf994c0a4262f802bf3fdf2fa3ed7b8167c7..c756923a7302cc6dc144e108a11a4d2ceb5800ed 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 89d0422a91a88fea51ecf5935d31c2920545f8a6..503c2451131e5ba78b26fcce09870b0ca1a3d9bb 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 23e363f38302a88af9d64e0003b8e144ed4228b0..13b691a8a7d2ea4403161213486538dadf75a217 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 65df7d8be4f587cbc703e3885b6f9a1d4050ffe0..48992cac714b413f644dbdd7c97ba87355831677 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 6c794085abaca594ddde671bdea5f6b79dbbb072..80d67253623cb20c16f9e47b9fef3633fcee64c3 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 6af66ee56390793ed3b1f718f2cb07cba8b92a50..4556ce1af5b04f5a4f0cd0b4e1ae0515435a1857 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 16a5047903a6ef3a89e031e61e4a9044fa9b99c9..406d9cc84ba8d99b7520b4ee931d9c010f9e5bea 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 f73991522672a665e92b13ac4433e6ce35935764..601afd1afddf5bca94fb35f993e61919b6bbdcd4 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 e4619b00f7c5dec65669f0b1dd9acdf135392185..fa35ff79ab358fe79c734f54ff51ebcb21ab9f7f 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 03310721712f7885aa043c1c2f88421d0a80649b..b6bd4affd9adb102d7d169aadc42e34da27e53ea 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 10d6c41aecad7bd4db25f65e652479f7536aaf3b..6bf06a07f3e00b56e3d738fd0cdd898521ec323f 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 c320ac52353e458723f46613893bcc0423ccc463..08b8ea8c353edaf4966fe0f385e1cc22691851dd 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 8f5074e1ecb9eaf2b39b0064edc17f5528516ca2..77640a8bfb87ec3d18d272d5f48c537ab29fa900 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 0af3349de8512b83c50b9ad406af972de7180186..03ffde1f44d699764ad7e956c8cbe60fc8428dd2 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 647d86d2db395028a47eed98be3f5264b715e8cb..81b4f643ecefda84444cca57481958bfca11ea06 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 60426ccb3b6561e25b050f50139df908a6b251fe..d5659d96ee7fc06554cc95e24202715c00380592 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 3c5dd55d284ce3baa24d3f2c4071ca53e883a223..b359d12eb359e2800cbe1ac7a9ae9bd8c558c7ff 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 31831afe1c3b26b954a279fb034b5e50649cc8cb..b9f69e1b1f434422ec0ca8435e1ac5cf6c087612 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 981a95617fc9fbcbd58051f6064aa7a757ac1c04..482387532f547fbc0e61def87d85c1dfb4b71ebc 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 3a1587222c8a7a3eeea9b2990a3d734d313e767f..04a69a4d8e9672519b4f1216f84cf0ab00d5698f 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 52439ddc8de051bc5693f14220e25ce2d7fcfe39..1a63bfdb4a6584eb10d6744aabeec27e940513d7 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 ae2e87b95453d2b21f746bdb931da675197ad0ba..41db5258e7a7a5ef837ebd11ae605f7144bd4e65 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 4a48fe4b84b68c4e704aea84ea761e101a5ad0df..d9f3d067cd15635ffd0bb569ef76a156a2d84630 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 5bb790a69c7165fd8319104ebbdc2a09848ab8b3..284ca901fe16cd26d064c603f2e51441708a5953 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 c4702baa22b83355efdb327335bd1a6af512affc..0c438973f3c8687836fc16bae3fb9aa89a767727 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 b46cf5a6732952460c68f6faeeb5479f355868d7..dd8bfc2e2464609dd7fa755afcff2b6f436f5def 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 a462ef0fb5d6dcda8bab6f211e8122d7d972b070..db60149c4579a9cfd9409ec355da9eeb2f254359 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 a5b27c2d9689f86704857b55365347e2f5c515d6..e1d1badbe53c32a1a4d9f9d4e4b83eb4c83a1b05 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 0e46d3d1b6cc6c06854517c66ab4aa5f783cfb9e..aa9ef4876046aa17cc43c201d33ba6dbe49f1b8f 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 450bfedbe2f4c0f88cacc44ec504872487279faa..397be39c6dc86623c27e08f2240efaecc2ec7722 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 0deb32105ccf3cb8b40fe95365f91f8b4b9c4da4..2349518eef2c28c9c74692335252b4a3877f4d22 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 72f3bf1754ef770c3c7b2f1346225e1440ec968b..73ce8d4fe2c8e2a34677efdeccccfd8e936195f4 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 4755858e37a0b93f64643811f683b0de7f0d6def..cb53d450ae321e4464e9dee7d9a4aa6ef2074b9e 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 fddbba2d9eff028fa5c15e12b799aedf35f40e4d..e55ce9e8b034e0c9372b209ac34213577cdd516a 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 11d78944de795be25d3232b795f677fd0fe64efa..de54129336c6d095984fd34c548491a2916e902b 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 a812fd1b92a4593fc744606e5ae15ff128c8e2c7..b481e1f5eeccb692dbd82e01c54f3c2d4093e0be 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 d190e33d0ec2fdeb845eec70ab3c610ab551758d..6f3f392d48af76d9b7bdb752f1d13eff9580be1b 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 7f05cd140de3cb2a8c75665bdbcad8bb3d823582..39c8ef875f91b5a93b57c8886b56569d679296a3 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 82189b208af31700418217e62d8339f13dce6565..d543222babf36beb28aba95afd746ddd9298d8ce 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 d5d070fbeb35a98f6053ae4299c225f57a8bdd74..3ba65979a3cde006e73ed2c310e2bc42f6988fb2 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 63f2395c57ed72bcb55cab62e1234d3c27bea0be..2723c1badd01276f9c1802d6cac210aa40f8f0a3 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 7f555179bf81b725364e558f76ba20ccfa2fb4ad..f34d9de802abc7bfea33c14388020abcfcd007dc 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 30f34ab02137f8e41aa95bcbf7c51967e694f3c1..479eb681c27c31ab5b55ce99cc79777cacb45721 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 4775bc4896c8b363123f852d1fd517f59fe7fd6e..ad67964d0bb198c0a516bb5adf10d31b060478f5 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 b17d93214d0153b426282b1f23e3414768fb6ca0..9c769a47ac5ab7efc9a2b939305ffbad45ed988f 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 915808b36df76142634478b02832c90676202275..16f0673a423c0884772cb2fffbfcf96b86cc3e65 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 d278a0d034968d3bdb57b7f942048af7e2ed6712..5ea7df30508370a5d348e89a3b3716f3b7afc1cf 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 08fdb77852acd4f2ca692c5c8eb010e55b00aaf5..f3a82fbcae026357431720d998b5eb6e7eafee66 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 807150e2c2b9871d640bf10b260f134f4430f46c..dd6103cc93c1b4cd50c14400372ecdfae33bfe91 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 53c27eaf2307500fc9ec616a3f38c09aea890cc2..61bf091e32a8d9166d0cd2710d3f52463fb9cbb2 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 bd5610d482423a0ddf8efaf865f368d66d005e9f..9de2491f29262ddf8c34a7a1f4d0e4f89c94f66d 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 a4b07730b2e1d0abb257a126fce7f3911ae1d434..b7f57271d49c7030f81de8779a78d0d64478ede6 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 5c8343fe74382e24a4a42c28ae30c1292ea4355a..83f1a665ae977634fa17ee8b15b9d4ae98abb5af 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 656e401794de5f8e2b03e975130cd3546ed5ed27..64db2bceac59e7634976235bcddeada98e592b1c 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 b9760628e1fde7b9a5c681798a65185144abeb92..6b7087e2e8fb059c36ac19e0013fc86f595e5149 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 985ea881b5bc489aa7ae0657e23fbe23d650d844..0788d093f5d86ace99ad80f68f4d7bd924eff294 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 8f20e3404fd2a711b3b6df63889971f78a157cdc..0adbc02d60e37b11942ef59dbda74b26f05a5f4c 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 136e548d9567feafaa6a695abf8dd3a9015c5a87..7445af0b1aa341adb9008d05494890f11c4a4568 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 fb52b548080da50cf2cece633c2585601485fc09..442177b1119a4528b08210a56f5188b3ef1f2a20 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 88d4585b30f1531b6e609825315d0868cc2edbe6..6a8e785b29da9d39f8cc258087fff94e3ef16af9 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 880fd988436695344ff58134ff839382a8003689..c51df1dd237e74a0127da81f95d77f570d463b84 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 1fd2051109a3547a47dbea91dc8e88ea5343d7c4..af677353a3f5b5d06960b47c7d1c313e02cfb5be 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 123c79b7261ef8092e57477bd1141d365a0a2a3f..4f34dbae823dc9930077a4599933e14b7e457de9 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 64f2b7334d08bf41f6ec9ed0910393eb680d9fbc..3286db047a40230f50cb5e18a177b744f150342b 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 a7ea492ae66072d34cb4daa4c99c51f3a5ea281c..0ab1de4b39a5d34b5e7eac5a90acd8d1aa8366f0 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 d0426d74817b68402e97a9794b2c54c7ac4690c2..98f7211599ffe747f15a9d916ccdb14e0cd3592a 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 b8c6791f046fbe4195d97697bbe8a6ba29be03a0..c1183f9f69dc71c3089951898043c582181092fd 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 f7abff8c16ca7361d3e32f1842ae1daed15e651e..003c0051b62fa34ce086154413095b4fbdb4317d 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 7d10f962aa137776389daf226b42b8be9702e1bd..630dd23722381851ae9f8ba3a838283f3a8aa8e2 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 d5afe96adba6c5ee239390625bbb93907c2cc1ba..975e1cc75edb55f9dcd19530eb08912b220e2641 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 6afd7d6a9899c49fe721a7bb989c947ea5dc9c75..1b41011643a5ebb694742f7a11ba6c54bba35a16 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 d17784ea37ff34e2a8c167736bdd3b13b5a34d2f..0703aa75b5e8eda4c8f469a74925e171804bdd92 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 04a7f31301f8fda61ab05cf42a3bea5c28431178..a7c2a862b4f48ab286f20b3860ea8eeb442bd1a9 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 8f3dee09757999c7c959e284250142c143d37d7d..e55fccbe7c42373940ff8fee459d076cd5e6d4bf 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 b1388b5fe7acd7d597f6345f273ce26de61d7535..0bb34ca2ad2be8983d21ff7ee7e67965fc6292c7 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 1d09050a8c001749ba26087581b93cb2de1f9153..b4f58914bf7d9374342c938ecada9ba52a7c82ae 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 0145b948b147e3647bca2b1fbb87f89edfdd38c7..6e622f7d481d85b76219edab75815423b69ba47b 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 89b4d7db1ebd3bae06c366bfcdc923b25cee242f..2a3cea91606da6f568f249b85f89130f8f7e89d8 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 d32628acdd90ed26b3ed6506faa9448092e232b2..7209df15a3cd1e1929989a180ff6aa5bf3ec86f1 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 cba67865d18f51adabf46f9a18c1071c4e47c19b..a24addfdfcec5568015e4e358402d6afa002e37a 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 c18a593d1744ac1d2197df11b3d2bfda9e6429eb..8cd402c73a5fdf4f9a934a4b33c7fffa1d639f90 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 884613ee00ad88bd6d60a2393d4021c70ac97551..87ac5e6ca5519bfc1e48081efd050532d51c61dd 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 32d34ebf0706fa8f73e793b035816fd7cfaa36a3..a5183da3ef924d0219a0571d55e6b14784ab54c9 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 0097cc03034e18b10e5ad9cdc34b9019eb821314..ed953f98f0e1446ce01630c005e406f941282347 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 c84ff153a564258f5e71404bfb50589b313c56f0..8ed44f9bbdfba00412df22a7ba16b71126e209cf 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 b4a745d7d9a9005b99970afc0ad595fb0efe8e85..61f29e5ea840bb2ba14420ecc29e63b996684281 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 138448f766b44fdf2939ac0eff1cad12c205240c..d12659ce550d2f160cf7a0bebdc51160b39a6c3a 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 25bfb0eff7720b459ffefa45ec035ec0229c8b1c..5f6db18d72e8845748a5b506949a1d7d1247cf06 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 fd47e872ebcc7a35380160dbf2f83ab1563dd878..94ec69672164c9dd84b41c1ab3a7c995a761c1fc 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 49ff69f0746bd6f28ee517ac6146716ff0e27fa5..561ea896c65701ec009fd4e860ed824a36e080de 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 96292df4041ba2aaebe32caa2dae5f731b4fb02c..f20e0d8a2155dc0f5d95ee248c2ed1aa56af1df1 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 03e962e23eaf65aad5d161c528ae6a43cdc0ffed..81887120395c81347c6a74ad3c92d847f3c4c90d 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 7032518f85424bb081d9f6a713fec67d45873d77..72ab536ad3de7614b4f9f84754457f391949de78 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 acaa5615d6343906ab05e528bb10ea3e76bf0fac..4fad5f8ee01d3457974551ef1f874fc61f0524f9 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 da74d878dc4f87ab64faba5981b8ad8edc6dbda6..df53e1753a76bffe0ff8fefa8c5a2a0ab8ad0790 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 9231be9e90a2261d6ad6a12b3f49d25e39df7229..11c0182a153b8a9025a4b4eab4486fe99a07949f 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 3af847273277785332e994aedc2559db74c1623a..d2b52999e7717252a743204817ef726fd94a3567 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 ade1c06d4cebed9c30b47ea98c69fe51df89508c..d2b16704624c6c6122a09457e00ef716ef8d0393 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 01f5951070489c0a48eeacc290b4428c203ed852..1c0134dd32718f1561c3ced6704f6b65edcad817 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 f669585c4fc5b70fea1a5f6eea058750c344e64c..6af3400b9b2ffc7040eb013df06b73d633d65768 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 8a18e75600ccb25b47f17decfacdef673de89713..b76e6e5458064551d53ae527281a8a353e9f6301 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 e2d28b026a8ca3fb362341decd8f1a6f64904ea5..3c77bf9b1efd03384d0c5527ce93431762252f65 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 08fb0247764177a8b96f83f5181a17c9d33b099c..4c52907a6d8b54d41fbd63cc1839f159c0ed5207 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 96549abe88424d43f5b50d2b78cbe77de7b4607e..0081f000e34b30f0ba0f6562274bb33a9ae0e74c 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 eccfb4a4b37928be40629c259f709e90f9f15620..b569b8be5c5ac49f918f5fdd492424530be8f185 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 5f1ea756aaceee191eaccb1e5c73ab7455636de8..3c1b968da0caaf71c55a557887f942cc98c845dd 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 3ddaa634b19d45102de7579169a5c50d05abe74b..7b35c21170d5938e86eda0d4541057bca0ede81b 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 21e21b81cc7551db7203b7d027b688feebd3577c..bba65f51a0b542c526e253a237e33eef0045c785 100644 (file)
@@ -83,6 +83,7 @@ enum da9052_chip_id {
        DA9053_AA,
        DA9053_BA,
        DA9053_BB,
+       DA9053_BC,
 };
 
 struct da9052_pdata;
index 2d2a0af675fd3f03f1354268c8afd884a94b2592..00a9aac5d1e87fe5a6fa53a00fc9390392c5b6c9 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 5834813fb5f31e69889b8b07c3d52fdf68257b8f..09a85c699da1d2f28abc88ecea590077c4c5edad 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 3e1df644c407ed6d6965dc62908cb620421ca70a..8feac782fa835e8a78c6b6b6ae65e5e4da6602eb 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 a3d0185196d36799ffc974b63148665316818718..c9b332fb0d5da1e11c0ac42c06bf62521541d55e 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 247b021dfaaf5de7b036917be4124742e00ea201..736d39c3ec0d7a4b115df93d97d60d84c4979a85 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,
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
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 35300f390eb6b732499d2ffd0b9c295f73d01e4d..abc848412e3c1c9cf34023690c9e80ecd00ab21d 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 290901a8c1de9f0193ae3e2c640c070623431081..2b58d192ea2401071c6a44d84286ba956acc939d 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 5042c036dda9fcddcef627743d588f62b5aa4aaf..2d57efa64cc168e5a033ace8079c102b9269fa6b 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 5a5053975114c962dd1d1cd1e9adc3e71da9bd23..f520a767c86ca7eb4e91a92d84f0c3f08c70e899 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 c3eb102a9cc81d8ed97f11deb9584aa71830b1c5..204a677438049b13570e779f36078e0450298614 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 8cc0e2fb68941f5169593076ad50411bb8939c85..a1b0b4c8fd79cd87bda46f1b15866a78dde89724 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 32f8612469d8d2d2c5a659f9326551bcbbd8806b..450d61ec7f060982ff65bea2de2d35e275028877 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 5a09a48f2658a64f7149ecddd30abd56c65cf69f..c26d0ec2ef3a90b7a988da8c31f9667716c78392 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 775cc956ff7874c5949ec707357341137c6fdb1f..7ed3a3aa6604b7b8511ea709ea2c2312a1d38bb2 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 0ae5807480f466af6fc9de106b29207bc03f9752..fa6918b0f8295296a04e89c01c3b685dd360e1aa 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 5624e4e2763c2eb3d73f4e02d2752661ccd9c6b9..6fb5b2335b59041fbc9b2b62ca063aa6235de470 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 cb32d9c1e8dc83502e39143a8c25913bab3193d5..e266caa364029fafba52d443931f76d3758cc099 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 e3817d2441b697c2042a9e4b7624d99333671cb3..e7a0b95ed5279bdbc6bd478d3c9bb0452e57958c 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 e56b07f5c9b67f0119d874b60a8a6bed9fda7e99..3356abcfff184e707eccb08d6f99042a8fd51acc 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;
index bf0a83b7ed9d3e0538cc09c57f7d498065931501..4edb40676b3f9b8b909e43a5b5af2bf6bb64efd6 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 b64115fa93a4dcff04adc74e24c8573388ac2db3..36bb92172f4795ff806275f8777d5ecf0bd93b1a 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 201a6974965925bf5f9424acf0b63f671efd3c60..56b7bc32db4f89aa924e5c02ae929af3a32fe83d 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 b71d5738e68345345bc1580abae26b2d8e582048..6bda06f21930bcce8ff57ad7eaa5f3afad8bf45d 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 7cb07fd266808835ca8d4309891f19567cbe7503..075b3056c0c00692e6f23cf17d45349323a9d5ec 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 b5b2df60299e25c5c33b3be39ff90090c974689f..3dd389aa91c7cc702c383c33efb20c3a79efc27a 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 f56bfa9e4526f6382467fe2647c19bdbca185346..f2f7398848cfed2b348222aae7573ad2c2a76ba8 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 bcbb642a7641d936c441e8c2211e9dc287513b6b..087b08a4d333a53f09b2e2bfcd0ea2fa68a608d3 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 969c0a671dbfbbab399f7472d501a93d75bbd8fc..2ca67b55e0fe2f0abf7e432ee8402608b6d57201 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 8af2804bab16645e0b625052daa90fe1dfabb194..70736b98c7215a3002efb69476cce71aced4e5bd 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 62fd1b756e9914a63ea72ae21a401a7b14115161..947009ed59969af2b79ca3f2a049eaec323f3f3c 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 8097b9df677326717517f256b66dbaa17e27df93..3e5efb2b236e2198847460cf2bd943b99b1b1cf0 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 2aa8b749f13d058b7c51c259da8bfed4d9c9eae7..697ceb70a9a9107689c1fc98f8599552314a9fd8 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 e0bf210ddffde0108e77820d81adc318332e2f19..084354b0e81451c651120afebdc75dfbaaec02f8 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 12ae6ce997d6be9f658fb2956a957966267028b5..7062330a13296188ae96448f4abec8a28617fe1d 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 ea4476157e00321a6888a3643789dbd7f0bc9634..45c9cd1daf7af5eb142e7d31ecc4389fdbd3daa6 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 559044c79232dcd27b18a3203d82295866fe949f..e7d9d9ed14f56252e5efe0a529e80f4dd050e1ab 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 021b8a319b9e2cf7f0f60a5f6fedcfe3367f8016..5777c13849ba828aefe843b560beb5511d823fa1 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 956b175523ffaf726dadb2fa079219e0d12d5838..55d15049ab2fd60626bb4a5305baf6df5978c791 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 1619327374164909b6f8aaea6a730b0821ec6ee2..11fd51b413de25a6a2415c1724dee458d3314ddc 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 102a646e1996694bd16b536ef9c292093115e39c..dee3bb1d5a6b5b28d001b98f46ea9694d7a6bb65 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 4164529a94f9f1529ac55c012d1d58d4a2dd6c2f..ddc3b36f1046bd6605ecdd769e4f70e59404e16b 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 b06c8ed687079759ea7e585589aac199ac288e22..9abbeb924cbb74a7e0bfba97d178831e92590d4f 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 d3c62074016ded5c99c7dfd045469b3519227485..0664c31f010cb49671cdae819d14fdda31ff01a8 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 d9ea3a73afe2d2a4df80ebebd23316df5077c346..aefa2f6afa3ba3ccba6b86826db289fa9b21a5d4 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 5e1ab552cbed31bacae535f03b6c43431af87d52..b042b48495d9a679dd0857d33e7d2bd377f7c5b1 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 87792a5fee3bad7d143de81555a56ede7e532f1a..4fc66f6b12ced39a20d5c03fd820d1b513cd507d 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 289760f424aaa3247d2e4f66841334c67295c9ef..58afc04c107e40cf9f481a7f9eefefd67dbe74ce 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 24f3a57022b8f3e242f7c09772804c44bb25cd57..6adb445346064e815bb5fbccc030a9d56e63c6c0 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 8851c64178801b0c893b1f4032768bff84d1b5ce..427ba60d638fce09ebbfcabba9ba9ccc42d11d02 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 93b61396756bcdddd9c38f9967cb0494fc580d7e..a8497fab1c3d64950370fb54401493e9eeac0621 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 a4695ada3275742e0bd5258e55ab046751fb38b4..45d035d4cedcfff58934b3f8e15aac4e6162d5de 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 17028648cfeb05fc4b76470ca343cd069a11bb02..998d31b230f1068678be01fa49248ea4e3fd693e 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 c3b31179122c326342597d40cd58db11d51da940..4fcf39af17768345be5f60e08e44af14b14bad76 100644 (file)
@@ -1459,4 +1459,4 @@ out_sysctl:
        return error;
 }
 
-__initcall(init_mqueue_fs);
+device_initcall(init_mqueue_fs);
index e1b4c6db8aa042d2a896426391b10af913ac7b4f..2eb0d1eaa312d9e0deda1faec271ea3bf55f8180 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 fede3d3f28ffaa5c998333706d5233620d0734db..9fcdaa705b6cb7442b4babcb3a9ab40564afa27b 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 deff2e693766997a259b4b3ac2fc4f789e554f1d..a9e710eef0e2543f063ee8a1c06952f2fb3e0891 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 99982a70ddade1f728e18bd1af020b3600c4b8a2..2956c8da16055a70c23bda77804b203abc9a6fe9 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 6480d1c85d7a294694bcb4163cb2976b238e0cac..6ed6a1d552b5d237cf391c38ff8a4dfdafdc7888 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 abc45890f0a504dbf428c96cc07942de4a476cf4..54a8d26f612f76f17cfb883e29786df98a9de0e0 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 67dacaf93e56c0edb12b74a84b40da9fe596ea49..6801b3751a95cd0933463fc38039cb77d6ced705 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 3127ad52cdb2eb8d61176f873503f62294db3827..cb0cf37dac3a4e0d3c4dd0562e18ad0046f0ff24 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 c0d261c7db7b8d418c148d7a177b07c3a304ea0d..c8380ad203bcd5fe8e78bf9570725730733791f0 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 e660964086e2e46d1066e143d29c21887f712d5d..2495a9b14ac8f1ffa67722de3bd410c6493d42e5 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 306a76b51e0f4308a1ef680e006e07333e98d3c0..b8bdcd4785b767d5fc1ee732d778b07ee74cf102 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 8dc7f5e80dd8f75273ef15df03a14615de1579d4..11869408f79b86abe33e5194d0f5c705b44e9d81 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 cca8a913ae7c8d6314fda34a1f3853a364e32cfd..d02fa9fef46ae14c218826e4c5e271ac8894aa51 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 1ca753106557f4d7de3f6586f86fe8f33593851b..15f37ea087191784e26a9d801bb128c5c3b43dd2 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 149e745eaa528800cd64a07bd8aacdbe6dd63ea0..18fb7a2fb14b315cf3f7f9a7bdaf0173438d57b5 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 90b3d9366d1a7d51338484b95b9a1084aa2992b8..c3ad9cafe930e550a6400dc1994f8ee86570d885 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 7c33ed200410843a97dc39f59da4080f270832e2..8c9a4819f798c8b41d74972dae361dc8d2c6eeb1 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 1b266dbe755a983e0bca02bb50ca1ab47419488d..cb980f0c731b72ef3df3ff6b9afa2f6f44d15b9c 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 4aa8a305aedeb23cf7ad15aa2750898057b3c0d4..51dbac6a363358b435a14f9e7952b9489eb3bf9d 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 b30a2924ef1429a60152a40101ec4828c5e23268..3ef6451e972ed06571b94a4d19a11d78edd39bf6 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 1d1b87b36778abf2fffe0a53e6f380ef36bf7334..268a45ea238cc84f51ae7612bf0ba3c531b9887f 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 5d4b05a229a66ee464fd8e22a64a458c4a30ca61..6ea13c09ae56027521d41f75430e8401cb32ad93 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 adaeab6f7a870ae69537baebf4ca092a161d5013..fba0f29401eafba43b29602b0296ee16022b4633 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 5c14b547882ef1dabfcd9cd80f5903e173ef4ec4..74f5b580fe34904fa4d9bcb2790545a323367773 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 5b40279ecd711d93074a33b0198dff6201c202e8..f7df8ea217079556ce483bf478f5891003804323 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 fc4da2d97f9b6e280b2e29a525e478958cb495d4..c634868c2921ca39837c3a36773c36fa4a3273d5 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 ffc314b7e92b165d35cebbd88d87d3293deb66e6..2e29d7ba5a52b05e6fc3749876de7d4a4566579d 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 50f8329c20425decc51420f5d733b15193a56091..fb0a38a265555c6c846254859c83468d0aba0f35 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 991c98bc4a3f51e9e7f377274084bec909483ea9..5d4984c505f8c10d0d7250b7f59d3234fe3b21b5 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 4d1cd0397aab0d9857f7a82f528c72946b520f87..86069d74c062d17ec094f44754ab197483bf910e 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 48cb3c7bd7de6e0e3382113c3b072373f0775549..2f16c133fd368c9508a7c3bccf60cbec49648e9b 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 1ba4956bfbff70cb8d295809577ea2c7cbfcebf8..2642fa8e424dc1a4db769b0eae5e5aa94997f53e 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 2c08f36862ebb378b487be2bc8103c7ab29d1124..fc3dcb4b238eca1a483c17de5b5706f536d3d444 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 8280a5dd172780371711743d297fcd0fd4e4360a..7dd33577b9058ea1569eda068ea437079f5bc65e 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 04abe53f12a18bd639c598eac2045fa866482774..1afec32de6f21c001447b6545b440aff6308bdd2 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 2888024e0b0abea6b6f37f4531ad0f8dfec5c7b3..ebe5880c29d6cbe2306054f19bda87ffb3daa59a 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 cdd741519ee0b1761f20890b3b3cf212998c4cbf..9e5aaf92197d3fcc7038e86d9769dc0def5bf1c3 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 b6ab771600680467609412552ccfacb177ed7973..37f976287068cef4ed185836059da2cc12cdceda 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 21781f1fe52b676e2b1f7dba5b2477f898503b1f..27ebc0c9571bb8831ceb38c4e71e1bf57227f098 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 6ac89e9f82efe0936df17931acc60503a9405c3b..64635f5278ff2d41525fe1ca3ebcf5314c95e3e4 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 7c02b9dadfb05b28e2aef363523f021f933bdb6d..dd30f22b35e0c904b0fe9cfd4f550b810e1e7c22 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 29e1e761f9ebe3fee42eea1b0e77589122a23d24..07b67361a40a2d4a83ad4e005a96b81d63e05239 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 7fe5354e7552c0507eb6a6b778eee42d1c2182af..e9d6ca9a01a9a3e0b1f56029a332b51c9202455e 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 dcc8153a1681bb1303616fa5e12cdd86e99291cf..29501f04056887297be694c315c7caf3adf666f5 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 82c1e4cf00d16644f04f4d36fd72a008ea978ed5..d0f0bef3be488af9eb9406cc5d28272093abb5a6 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 e3ab02822799d2527949fc4476a380820aec5371..78e1472933ea0fce8ee57b94ed3d3d9a3b52b3fc 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 659aa42bad1621756878dc41ce65e3cbd86ed0fb..905434f18c9738a18cd20364131a952336325411 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 4e1a68162285688ad1f1158681a6908e7e237924..b1eb53634005606298d115ac5cdeb90cac923957 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 46433e137abc2ef4f22486d426d43df5c54e9589..b1202cf81f4bddf1dcc8393f1231ed85b1e64e6e 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 769a67a158037197341742104d2a9023cb1e03a0..c43d557941f807471a3c39963f77a8ba3d32dd8a 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 a554e5a451cdb4622d32ce1a5b6cacf1773f848f..85f8d6698d4872c62ce3d3a03504c314b029215e 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 7106cb1aca8e3733059b344a773310aa4bf0fcd7..ef413492a14945c5e7ab0f5a8d33bd66eaf34873 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 979378deccbfcc22fc1a120e08248dbad1053ab3..5dba2933c9c018b59178a5e88df54db01a7fe41a 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 29c5e1af5a0c79a5af00f097c2a03b7492316c8c..0ca36a7770b1b974eaea70d6357b7cdbd73aad3d 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 11cf322f8133d7048d414c6f0eed227f6b12d3ac..9c3e77396d1a118edb8f2de7d16ff835ed214f0a 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 a3ba988ec94612c4774459caac87c4c30c181158..70273f8df5867a33aeea7267e4268a949a35aaaa 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 9153c802e2fee1898c62ea1cdcb5efecb3bbc2ed..3db4cb06e32eac698fcdb3d531d8c4f910824b8d 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 8184a7cde272b8aa9d6e08e6407482ca5d7bd7df..3045316b7c9df285e04b3954c1921f7542f2311a 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 1ec3c619ba04b955f0d64f32ae3d432d113488f6..f3cfccf76dda693250106d3c8d0387292e741c14 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 fe6d7be22ef09b30c33dff7c57665b750b0610bf..f620bbf4054aa0c1cc771873a8fe3463856f2fcc 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 38cad8fd739734573ce90a3c9b1c251116f01193..d1b48b691ac8c20040a262337cc7e0cbf566420f 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 a24aa22f2473690c1e2fa95514f778c6c0c616a7..d7813e6d4cc7c042c44a01692f0993a2b6bad04a 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 0fdf96803c5b59623792a24e57015fb0e25098bb..bf233b283319cea03fcf76f2d81dce5b9933d536 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 1f56a80a7c41442eefa86d7fe82387570cb3bfd0..9b6497eda8067857d7008787868e365882820db3 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 197b4c4a95879832e29e7b933b70c2f4f6e01d17..302dd076b8bf47bfb13a7925166b1b1f4e0dc5eb 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 c03ca5e9fe15c8b9725db0ac41b6ba78f64b0e5d..36b4591a7a2d3b2eca7111b26bee3efa19c7c5c5 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 e55bab9dc41f81ab1b6384710e918f3839e0c936..aeaef0fb562400093a91517e9ce62ca63cb94bed 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 0e474b13463b95a90a185f883d3435db346efa34..1059ed3bc2557d597cb0548962a888e544d74a67 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 b703790b4e44788e109bb91ab61f272015000654..a1ef53c044151be9df2ac4e61e0631226d59f0a8 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 258a382e75ed665a597d063a1234150e47d8f5f0..10421a4b76f8710def7328e45dabf227cc3cdb3b 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 30efc5c186222c64ea3d7d21b194f8ce9f4e0f47..4f55f9ce63fac652f789353c6c3dc6f0e932951b 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 82750f9158655225ad7dab9e903932d38f97b8a5..b0dfce77656a0ba9c43d6d6616be1d28fb4dc137 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 aade4a5c1c07f6ab0ca0f1ee66dfacbded110aed..e632b5a52f5b89cb2e275b64494905cc7ebfc8e7 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 757063420ce0f2144d90fc6eeb67f0c44ef57126..14dac0654f28c273d8ebd7df001adb9d86934443 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 30071dec287a4674b64ec4f29c158d8a0a57bf56..640ba0e5831ce0334a9cbf03983c16a022e85065 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 765556ba32efba29ccdd8269a2c4f9a7b4a092dc..e08b3822c72a8bb67eeb4e8c3f139aebdb7b9d5a 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 31cfb365e0c689ffa528bf2f96072c6bcbc82799..a0348fde1fdfe89844352702565d35ef8d706f24 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 d0dac57291afab943db9719aa5818ebb6611cf65..d068ec25db1ee42982ed4e6d934de612d9b09a26 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 59da7cde072447c2331422659adb7dadad4f3fae..f95b6f93814b95b2c810eff8d4573a996f9a9f63 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 718dfbd30cbe09560c1d545525b446fb5695f6af..99e810f84671bbdb80e33c6915cc7be49ba0f1bb 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 1be9e990514da98dbc651f847f5b429d72889da6..34d094cadb11a3ef9b8351140e9c0ae4d60a4d1e 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 710238f58aa93c0319cf90adb0c203c35f8bc7e4..e080fbbbc0e5ce8d4d71014eed149e6b34250b62 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 cd5b8ec9be0459db10432aad57836f96b3388d63..da787930df0ab643a81bfa1f3f554efb2cd41bee 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 153bd1ddbfbba782b4c2842d7559d8a8917bb474..f0991f2344d403f3b1ed3a1f44fc2aebf50c72b4 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 33045a56229769502532b38e7b4a1bc5d89c80d8..3fd159db9f06bc31d3da81d8cb3e5e8f2bb3ebc2 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 9a8e77e7f8d42d4e3c7dd02d9c80b4a54311f5b0..f4e833005320fa7da4c0deb41bba272e8c54bd8e 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 458464e7bd7a841915aeebdd448cb17bb49c01e4..fbc66bb250d54de3d8cac6254110fedf1af7dd01 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 7174611bd67294179e3456c06ab4c7155e71a77a..c529161cdbf8906eeacacca22358ee26d25d3f9f 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 01039d2b16955ad459c4e14362b940ef794beed1..72e0c71fb01dddeee530067b341601d7196b25b3 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 981aaf8b6ace45e55b80a235ebbb9dfcb693d64b..5f83a6a2fa67e9101ca839cf63c7fd411a0e30d2 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 241b54f30204a63ec4a63372910a8c1fe714dbad..0754d0f466d2966eb5f5ef416e4b6e1661d0b1cc 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 8209a0411bca18ca92f5d13175bc04ffa09d1812..e5a7a1cac8f3f22b53278cf1b8104770c5aef969 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 e860d4f7ed2accd100c9ae9f715018daaae469a1..3513d559bc453d1465fda21d8860db601506bc06 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 0edada973434e4df883f63a85173f4a7a1de0885..2e6ab10734f6869af45a422bad6253e9de5cd580 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 ff3cc4bf4b24bc868088a67dd9ad92d40e42f066..25578afe15489b419409af91c97d396fdcb6404f 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 b6e59f0a9475d665ea1952a8428e56ed6b06b89e..d06cb8752dcd72de2aeae7ddbe7262aa435e46a1 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 1504bb11e4f351d1a79835fa990ac8f22751faf3..dd97ba3c4456d174c694cbbe034c7299acd642b1 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 7d4df99f761faa27de43af1b27640e412a3dc8a0..d173f79947c6bc6ceb0134d4c9e10fb3d767e92b 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 5a8f268bdd30c5dedfcb73dc6b071c1263553875..da5136fd56943fa91e20946d2a89346c3da556b2 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 e03725bfe2b8d35b2e496e4836a2d126c4f8b989..96ead526b1255d278c47cb8591065f4ad393814f 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 0ce75524ed2159982414da7cbf304a0ff3db7044..8d904e4eef1551f1c3a3c9281b5aa7a7ae39fb66 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 c1d124dc772be5f9381f11ad87d9519c5e200613..7e024a51617e034811a950bb245d1f615e9809a9 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 62e4f9bcc387182f829cc5c7d7559b0c16cfee34..25688fa2207f96a495a11e2ff8577032d24ff294 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 285dc08841159e609524897e6efcce564a1d25c7..1eb9c468d0c9b9db32895fa4e0f07366db135b63 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 0addefca8e7757d78571928580d6f7473a1354ae..6735e1d1e9bb4dcf6c550c20e622bbeb43dc335c 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 0374a817631e47fc87a6f9d9ec04c34009063e53..4c564eb69e1ad9bd2695e78eb91464a0112e663c 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 29b7f26a12cf6b29c0bac4c65354385fad036391..adc12e2273032f8eeb9c19b099510562d9607837 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 93a0da26582b863c64efd5ff226a8386bfb58064..122f95c958693c8b784e0b2e3e6409ab23d3e561 100644 (file)
@@ -3,6 +3,7 @@
 
 # Convenient variables
 comma   := ,
+quote   := "
 squote  := '
 empty   :=
 space   := $(empty) $(empty)
index 01e7adb838d93287d391ec4fee925936115877c1..1d07860f6c423661417d11fcfde21a8207f6de43 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 72105d10435710c52556aa824d7710ed4b8ad402..6a5b0decb797227326acb4f8511256afb003b989 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 10085de886fef49b78a12746a2e0a593545d56e0..1237dd7fb4cac7c2f863b413399df17a9e0c8beb 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 87f723804079ed3b6c1fbb0d1470f717582c4a28..f88d90f20228e8783b5ca39accc436140af7b3ff 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 ba663e1dc7e35b7bf732c4863c1202e3249ac636..412ea8a2abb8b80c6f0a889e2fb9d7b55bf0bafa 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 09f4edfdc91132887e1e54e09faf1a9b99865965..d5daa7af8b496e89143b3fd222fc3c35e7eeb748 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 db1512ae30cc48d6f2ea87bc26a082a084551811..3ac2c9c6e280300275920d2ea1cadb0c7be66746 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 f14ab41154b665c5759e3234201296a0cfbd43aa..b6ac02d604f1fbcca8ecc04cf09ac038bcb81fa8 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 40df0005daa928d4684555297c2243d0aef45171..c77a8eff1ef21ef6d5a05d588d732a892f50d2cb 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 2dcb37736d8469a0e18e4c1ba262281e3fd8cf37..86a4fe75f453735936e3b218f885dcd887216659 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 25f6f5970552224f07145f5bc2f093a7f8e925c9..1924990a737f36c61820bd35470c9adf90f49888 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 affa13480659e4b302606b182ae5e4dc6d72de6f..0216475fc759e23442a9f2ab7775c6966458b2cd 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 0b0c0cf13f748e0e231a6d068351c6827a57d128..3a3a3a71088b02eb9fa63d281cbb27f812a3328f 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 f9be24d9efacbde91935eb5d981c57d5548a9afa..05654f5e48d5f527939e2dfe62d98310f3831edb 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;